Khtml

What Safari Means for KHTML

I have spent enough time explaining that Konqueror is not merely a file manager with a web page bolted onto it. Now Apple has provided a rather convincing demonstration for me: Safari uses KHTML and KJS as the basis of its rendering engine.

The obvious reaction is pride. A small, portable engine built by the KDE project was good enough to become the foundation of Apple’s browser. That says more about the quality of the code than a dozen benchmark charts could.

The practical implication is more interesting. Web authors who previously tested only Internet Explorer and Mozilla now have a commercial reason to care about KHTML behaviour. Fixing a standards bug in KHTML can improve two browsers, and work done by Apple can potentially flow back to Konqueror under the LGPL.

“Potentially” is doing some work there. Apple’s first published changes arrived as large patches against old snapshots, which are not pleasant to merge. Source availability is not the same thing as easy collaboration. A patch the size of a small moon is technically useful, but it does not make the maintainer’s afternoon better.

Still, this is a very good problem to have. KHTML now has another serious user, more testing, and engineers being paid to improve it. KDE should be friendly but firm about working in manageable changes. If both sides manage that, Konqueror users may benefit every time Safari improves, and the web gets another standards-minded engine instead of another collection of browser-specific tricks.

Testing KHTML with a Small Page

A page rendered incorrectly in Konqueror today, and the original example was nearly two hundred lines long. CSS, tables, scripts, and invalid markup were all competing for suspicion. Reading KHTML code at random was not going to settle the argument.

I reduced the page until only the bad behavior remained:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
  <title>KHTML test</title>
  <style type="text/css">
    .box { width: 120px; padding: 10px; border: 1px solid black; }
  </style>
</head>
<body>
  <div class="box">A small test.</div>
</body>
</html>

That small file answers several questions quickly. Does standards or quirks handling matter? Is the problem in parsing, style selection, or layout? Does removing the width make it disappear? It also gives me something suitable for a regression test rather than a private copy of somebody’s entire site.

Konqueror embeds KHTML as a part. KHTML parses the document into its DOM representation, applies style rules, creates rendering objects, and lays them out in the available view. A symptom on screen can therefore begin much earlier than painting. If the DOM tree is wrong because the markup triggered error recovery, adjusting the renderer only conceals the first mistake.

I use khtml’s debug areas selectively when running Konqueror from a terminal. Turning on every message produces a heroic quantity of text and very little enlightenment. A focused trace plus a ten-line document usually beats scrolling.

I also check the same local file after clearing variables from the experiment: no proxy, no stale cache, no external style sheet, and no script unless script is essential to the failure. Then I add pieces back one at a time.

When the reduced case involves script, I separate the DOM mutation from the layout result. First I save a static document representing the tree after the script has run. If the static page still fails, the problem is no longer dependent on timing or the script interpreter. If it succeeds, I inspect when the mutation occurs and which notification should have caused style recalculation or layout.

Fonts can produce similarly misleading reports. A line wrapping differently is not automatically a box calculation bug. I note the selected family and size and try a common fixed font before changing layout code. Image dimensions and delayed loading deserve the same treatment because they can trigger a later relayout.

Finally, I state the expected result in plain words beside the test. A small HTML file without an expectation becomes a puzzle for the next person, who may reasonably conclude that the current rendering was the intended one.

My preference is to preserve the smallest failing page alongside the fix. The caveat is that reduction can accidentally remove malformed input that caused the original path, so I keep the original page until the reduced case is proven equivalent. Minimal examples are excellent witnesses, but occasionally they change their story under questioning.