<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Omoikane</title><link>https://blog.ast.moe/en/tags/omoikane/</link><description>Recent posts: Gorimuchu</description><generator>Hugo</generator><item><title>After implementing Omoikane’s DOM and exception notifications, we ended up investigating copying and garbage‑collection lifetimes as well.</title><link>https://blog.ast.moe/en/blog/2026-10-10/</link><pubDate>Sat, 10 Oct 2026 17:42:29 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-10-10/</guid><description>&lt;p&gt;We added DOM operations such as &lt;code&gt;before()&lt;/code&gt; and &lt;code&gt;replaceChildren()&lt;/code&gt; to Omoikane, along with &lt;code&gt;window.onerror&lt;/code&gt; and notifications for unhandled Promise rejections. [&lt;a href="https://github.com/ieee0824/omoikane/pull/1322"&gt;PR #1322&lt;/a&gt;](&lt;a href="https://github.com/ieee0824/omoikane/pull/1322"&gt;https://github.com/ieee0824/omoikane/pull/1322&lt;/a&gt;) This is about that pull request. The initial issue was straightforward: the page lacked the APIs it normally calls. However, as we progressed with implementation and testing, we ended up fixing issues such as copying sibling lists when inserting HTML text, rebuilding the entire document after UTF‑16 appends, creating unnecessary iframe realms, and even addressing insufficient GC roots for Promises.&lt;/p&gt;</description></item><item><title>WeakMap and Generational Garbage Collection</title><link>https://blog.ast.moe/en/blog/2026-10-08-2/</link><pubDate>Thu, 08 Oct 2026 21:52:45 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-10-08-2/</guid><description>&lt;p&gt;Opening &lt;code&gt;https://tokyo6.tokyo/&lt;/code&gt; with Omoikane caused a bug where the script terminated with a SIGSEGV during execution. Issue #1223 (&lt;a href="https://github.com/ieee0824/omoikane/issues/1223"&gt;issue #1223&lt;/a&gt;) reproduces the problem not only in the GUI but also in the screenshot feature that renders the screen to an image. The backtrace from the debug build reproduced on a Linux aarch64 Docker development environment with Xvfb showed that Boa’s garbage collector halted while traversing references to an object.&lt;/p&gt;
&lt;p&gt;The fix in &lt;a href="https://github.com/ieee0824/omoikane/pull/1260"&gt;PR #1260&lt;/a&gt; (&lt;a href="https://github.com/ieee0824/omoikane/pull/1260"&gt;PR #1260&lt;/a&gt;) addressed the combination of an ephemeron—a conditional reference—and the generational garbage collector. A young object that was referenced by an older object was being reclaimed during the minor GC that followed a major GC. Subsequently, the major GC followed a reference that had already been freed, causing a crash.&lt;/p&gt;</description></item><item><title>The object returned by Boa’s getter was collected by the garbage collector while the inline cache was being updated.</title><link>https://blog.ast.moe/en/blog/2026-09-30/</link><pubDate>Wed, 30 Sep 2026 08:12:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-30/</guid><description>&lt;p&gt;When running the test for a custom element associated with a form in Omoikane’s Web Platform Tests (WPT), it caused a SIGSEGV. The first occurrence was in a configuration that included the JIT, so we initially suspected an interaction between Boa’s JIT or its garbage collector. However, even when the JIT was disabled, the same crash could be reproduced (&lt;a href="https://github.com/ieee0824/omoikane/issues/858#issuecomment-5890658215"&gt;issue #858&lt;/a&gt;), and ultimately the problem lay in a tiny interval between when the getter’s returned object was produced and when it was stored in the VM’s registers.&lt;/p&gt;</description></item><item><title>Since generating realms with Omoikane was slow, I looked into Boa’s scope lookup and lexical analysis.</title><link>https://blog.ast.moe/en/blog/2026-09-29-2/</link><pubDate>Tue, 29 Sep 2026 18:25:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-29-2/</guid><description>&lt;p&gt;In the blog post investigating Omoikane’s CI wait times, we wrote about avoiding heavy verification for changes that only affect documentation and about revisiting the build cache. Separate from that, the tests that actually needed to be run were also taking a considerable amount of time. (&lt;a href="https://blog.ast.moe/en/blog/2026-09-29/"&gt;source&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Omoikane uses Boa to execute JavaScript. Each time a JavaScript realm is created for a page or an iframe, a large script that sets up the DOM API is run. This processing accounted for a substantial portion of the test runtime. In &lt;a href="https://github.com/ieee0824/omoikane/issues/1154"&gt;Issue #1154&lt;/a&gt;, instead of reducing the number of tests or realms, we investigated this initialization itself.&lt;/p&gt;</description></item><item><title>As AI-driven development progressed, the 30‑minute CI wait became increasingly burdensome, so I revisited the validation of Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-29/</link><pubDate>Tue, 29 Sep 2026 10:20:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-29/</guid><description>&lt;p&gt;When developing with AI coding agents such as Claude Code and Codex, you can work on implementation and research in parallel. Tasks that used to take one at a time can now be tackled multiple on the same day. However, the CI that runs after a pull request is submitted does not speed up to match your pace.&lt;/p&gt;
&lt;p&gt;My custom browser, Omoikane (&lt;a href="https://github.com/ieee0824/omoikane"&gt;source&lt;/a&gt;), has a large Rust codebase, and the internal Boa component resides in a separate Cargo workspace. Testing spans Linux and macOS, various architectures, WPT, and more. Because Rust compiles based on dependencies, features, and targets, this setup especially highlights long build wait times. Even if the agent can generate the next change, the verification of previous changes keeps piling up without finishing.&lt;/p&gt;</description></item><item><title>Tracing with Omoikane how a URL fragment becomes the CSS :target</title><link>https://blog.ast.moe/en/blog/2026-09-27/</link><pubDate>Sun, 27 Sep 2026 22:31:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-27/</guid><description>&lt;p&gt;Links that jump to headings on the page look simple.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;#details&amp;#34;&lt;/span&gt;&amp;gt;Go to details&amp;lt;/&lt;span style="color:#f92672"&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;section&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&amp;gt;...&amp;lt;/&lt;span style="color:#f92672"&gt;section&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you click this link, the URL’s end changes to &lt;code&gt;#details&lt;/code&gt;, and the corresponding element becomes the destination within the page. By using &lt;code&gt;:target&lt;/code&gt; in CSS, you can highlight only that element.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;outline&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;px&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;solid&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;red&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Usually, understanding that “the part of the URL after &lt;code&gt;#&lt;/code&gt; matches &lt;code&gt;id&lt;/code&gt;” is sufficient. However, when trying to incorporate &lt;code&gt;:target&lt;/code&gt; into my own browser, &lt;a href="https://github.com/ieee0824/omoikane"&gt;Omoikane&lt;/a&gt;, that wasn’t enough. The URL‑parsing logic, the HTML rules for selecting the target, the document’s internal state, CSS selector matching, and the updates after changing &lt;code&gt;location.hash&lt;/code&gt; are all handled in separate places.&lt;/p&gt;</description></item><item><title>Fixed the origin‑boundary bypass that was present in the internal host function of Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-26/</link><pubDate>Sat, 26 Sep 2026 07:06:58 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-26/</guid><description>&lt;p&gt;During the development of Omoikane, I happened to notice that the internal &lt;code&gt;__omoikane_*&lt;/code&gt; function was visible from the page’s JavaScript. By examining the code, I confirmed through static analysis that passing a different Document or Node ID could create a path that reaches the DOM, cookies, or storage of a cross‑origin document without going through the same‑origin policy. I did not create a proof‑of‑concept that actually reproduced the read/write behavior before the fix. After the fix, I verified in regression tests that cross‑origin access is properly blocked.&lt;/p&gt;</description></item><item><title>JavaScript Realms as Seen Through Omoikane’s iframe Implementation</title><link>https://blog.ast.moe/en/blog/2026-09-25-3/</link><pubDate>Fri, 25 Sep 2026 19:04:46 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-25-3/</guid><description>&lt;p&gt;When working with iframes in my custom browser
&lt;span&gt;
&lt;a target="_blank" href="https://github.com/ieee0824/omoikane"&gt;
Omoikane
&lt;/a&gt;
&lt;img class="external-link-icon" src="https://blog.ast.moe/images/outer-link.png" width="12" height="12" alt="" aria-hidden="true" loading="lazy"&gt;
&lt;/span&gt;
, I kept coming back to the concept of Realms. At first I thought of it as simply “creating a separate JavaScript execution environment for child frames.” However, merely creating a separate environment wasn’t enough. When a parent accesses the child’s &lt;code&gt;Array&lt;/code&gt;, when an iframe navigates to a different page, or when a timer that was scheduled in the child later fires, it becomes necessary to determine which Realm’s values are being used for which Document in each case.&lt;/p&gt;</description></item><item><title>A SIGSEGV occurred after garbage collection because the iterator function passed to Boa’s Array.from was not properly retained.</title><link>https://blog.ast.moe/en/blog/2026-09-25/</link><pubDate>Fri, 25 Sep 2026 08:46:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-25/</guid><description>&lt;p&gt;While running Omoikane’s Acid3 test, the process hit a SIGSEGV under the baseline JIT configuration on macOS ARM64. I briefly mentioned this in the earlier blog post about Omoikane updates, but the cause wasn’t the test itself nor the JIT’s machine‑code generation; it lay in the Boa code we’re incorporating, specifically in the &lt;code&gt;Array.from()&lt;/code&gt; section. Omoikane incorporates Boa’s source code together with the browser‑side implementation, so the fix was also applied to the engine that pulls in that code. (&lt;a href="https://blog.ast.moe/en/blog/2026-09-20/"&gt;source&lt;/a&gt;)&lt;/p&gt;</description></item><item><title>I advanced browser compatibility for cookies and scrolling in Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-23-2/</link><pubDate>Wed, 23 Sep 2026 21:39:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-23-2/</guid><description>&lt;p&gt;In my custom browser
&lt;span&gt;
&lt;a target="_blank" href="https://github.com/ieee0824/omoikane"&gt;
Omoikane
&lt;/a&gt;
&lt;img class="external-link-icon" src="https://blog.ast.moe/images/outer-link.png" width="12" height="12" alt="" aria-hidden="true" loading="lazy"&gt;
&lt;/span&gt;
, I made several changes related to Web API and CSS compatibility.&lt;/p&gt;
&lt;p&gt;Looking at these changes, many of them went beyond simply adding APIs visible to JavaScript. It was necessary to convey the page’s state to the host, reflect JavaScript actions in HTTP communication, and preserve the scroll position set by CSS until the input processing is finished.&lt;/p&gt;
&lt;h2 id="cookies-were-handled-separately-for-javascript-and-http"&gt;Cookies were handled separately for JavaScript and HTTP&lt;/h2&gt;
&lt;p&gt;The first thing we fixed was how cookies are managed.&lt;/p&gt;</description></item><item><title>I'm fixing subtle web‑compatibility differences in Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-22/</link><pubDate>Tue, 22 Sep 2026 07:09:00 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-22/</guid><description>&lt;p&gt;When I’m tinkering with my own browser,
&lt;span&gt;
&lt;a target="_blank" href="https://github.com/ieee0824/omoikane"&gt;
Omoikane
&lt;/a&gt;
&lt;img class="external-link-icon" src="https://blog.ast.moe/images/outer-link.png" width="12" height="12" alt="" aria-hidden="true" loading="lazy"&gt;
&lt;/span&gt;
, I’ve found that the tiny differences that are taken for granted in existing browsers can be more troublesome than implementing a single large web API.&lt;/p&gt;
&lt;p&gt;The changes I added this time are the default margin for &lt;code&gt;body&lt;/code&gt;, declarative Shadow DOM, and the orientation of characters in vertical text. Each of these looks like a small visual tweak, but each relies on assumptions in the CSS cascade, HTML parsing, and text rendering, respectively.&lt;/p&gt;</description></item><item><title>Implemented Pointer Lock and form‑related custom elements in Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-20/</link><pubDate>Sun, 20 Sep 2026 11:25:48 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-20/</guid><description>&lt;p&gt;I added Pointer Lock support and custom form‑related elements to my self‑made browser (
&lt;span&gt;
&lt;a target="_blank" href="https://github.com/ieee0824/omoikane"&gt;
Omoikane
&lt;/a&gt;
&lt;img class="external-link-icon" src="https://blog.ast.moe/images/outer-link.png" width="12" height="12" alt="" aria-hidden="true" loading="lazy"&gt;
&lt;/span&gt;
).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.ast.moe/en/blog/2026-09-19-3/"&gt;In the previous post I wrote about Fullscreen API and character‑encoding conversion streams&lt;/a&gt;. This time I’m covering the pathway for delivering mouse input to the page and the logic for integrating my custom input components into HTML forms.&lt;/p&gt;
&lt;p&gt;Neither of these is a huge undertaking if you only consider the entry‑point APIs. However, when we actually hooked everything up, we ran into issues such as mouse input being delivered twice on X11, iframe callbacks executing in a different runtime environment, and even pages that don’t use forms becoming sluggish. In the end, the macOS tests caused the entire process to crash.&lt;/p&gt;</description></item><item><title>Implemented the Fullscreen API and character‑encoding conversion streams in Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-19-3/</link><pubDate>Sat, 19 Sep 2026 20:46:07 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-19-3/</guid><description>&lt;p&gt;I added the Fullscreen API and &lt;code&gt;TextEncoderStream&lt;/code&gt;/&lt;code&gt;TextDecoderStream&lt;/code&gt; to my custom browser,
&lt;span&gt;
&lt;a target="_blank" href="https://github.com/ieee0824/omoikane"&gt;
Omoikane
&lt;/a&gt;
&lt;img class="external-link-icon" src="https://blog.ast.moe/images/outer-link.png" width="12" height="12" alt="" aria-hidden="true" loading="lazy"&gt;
&lt;/span&gt;
.&lt;/p&gt;
&lt;p&gt;Previously, I implemented the Popover API and a top layer (see /blog/2026-09-14/). This time, I connected that rendering pipeline to the Fullscreen API and, as a separate task, made character‑encoding conversion usable via the Streams API. (&lt;a href="https://blog.ast.moe/en/blog/2026-09-14/"&gt;source&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Fullscreen display and character‑encoding conversion are fairly unrelated features. However, neither could be completed simply by adding a JavaScript method.&lt;/p&gt;</description></item><item><title>Implemented the Popover API and top layer in the custom browser Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-14/</link><pubDate>Mon, 14 Sep 2026 16:34:41 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-14/</guid><description>&lt;p&gt;I have implemented the HTML Popover API in my custom browser, Omoikane (&lt;a href="https://github.com/ieee0824/omoikane"&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;With the Popover API, you can open and close popovers using only HTML, without needing to manage their visibility state with JavaScript.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;popovertarget&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;menu&amp;#34;&lt;/span&gt;&amp;gt;Open menu&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;div&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;menu&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;popover&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;Item 1&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;Item 2&amp;lt;/&lt;span style="color:#f92672"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At first glance, it seems all you’d need to do is add an API to toggle the element’s &lt;code&gt;display&lt;/code&gt; state.&lt;/p&gt;
&lt;p&gt;In reality, popovers are rendered on a top layer that lies outside the normal stacking order. There are considerations such as light dismissal when clicking outside, closing with the Escape key, focus movement and restoration, &lt;code&gt;::backdrop&lt;/code&gt;, and the ordering relationship with dialogs.&lt;/p&gt;</description></item><item><title>I investigated why Acid3 was crashing due to memory errors in Omoikane’s baseline JIT.</title><link>https://blog.ast.moe/en/blog/2026-09-13/</link><pubDate>Sun, 13 Sep 2026 20:20:51 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-13/</guid><description>&lt;p&gt;While working on implementing CSS in my own browser, Omoikane (&lt;a href="https://github.com/ieee0824/omoikane"&gt;source&lt;/a&gt;), Acid3 began crashing due to memory errors.&lt;/p&gt;
&lt;p&gt;The problem only occurs when the baseline JIT is enabled; it runs fine with the interpreter.&lt;/p&gt;
&lt;p&gt;Furthermore, Omoikane’s Acid3 runner has two execution modes, Faithful and DirectDrive. Faithful completes all 100 points, but then it crashes during DirectDrive.&lt;/p&gt;
&lt;p&gt;The failure manifests differently depending on the environment.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;Observed failure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;x86_64 Linux&lt;/td&gt;
&lt;td&gt;SIGSEGV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64 Linux&lt;/td&gt;
&lt;td&gt;SIGABRT, ~60 GB allocation, SIGSEGV on rerun&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARM64 macOS&lt;/td&gt;
&lt;td&gt;SIGSEGV, SIGBUS on rerun&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Even though it’s the same test, the signals differ.&lt;/p&gt;</description></item><item><title>I made significant progress on the HTML and CSS implementation of my custom browser, Omoikane.</title><link>https://blog.ast.moe/en/blog/2026-09-12/</link><pubDate>Sat, 12 Sep 2026 19:51:40 +0900</pubDate><guid>https://blog.ast.moe/en/blog/2026-09-12/</guid><description>&lt;p&gt;These past few days, I’ve been working on advancing the implementation of HTML and CSS in my custom browser, Omoikane (&lt;a href="https://github.com/ieee0824/omoikane"&gt;source&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;At first, I displayed the same HTML as Firefox and investigated where any rendering discrepancies remained.&lt;/p&gt;
&lt;p&gt;When I began the comparison, I discovered not only simple color differences but also fundamental shortcomings, such as inline elements not having their bounding boxes correctly calculated, web fonts not being manageable from JavaScript, and HTML fragments not being parsed according to the context.&lt;/p&gt;</description></item></channel></rss>