Beruflich Dokumente
Kultur Dokumente
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Reporting Bugs
You have found a bug? Here are 5 steps to getting it fixed!
To make sure you're not wasting your (and our) time, you should be using the latest version of
WebKit before you file your bug. First of all, you should download the latest nightly build to be
sure you have the latest version. If you've done this and you still experience the bug, go ahead
to the next step.
2. Search Bugzilla
Now that you have the latest WebKit version and still think you've found a WebKit bug, search
through Bugzilla first to see if anyone else has already filed it. This step is very important! If you
find that someone has filed your bug already, please go to the next step anyway, but instead of
filing a new bug, comment on the one you've found. If you can't find your bug in Bugzilla, go to
the next step.
3. Create a Bugzilla account
You will need to create a Bugzilla account to be able to report bugs (and to comment on them).
If you have registered, proceed to the next step.
4. File the bug!
Now you are ready to file a bug on the WebKit product. The Writing a Good Bug Report
document (also linked in the sidebar) gives some tips about the most useful information to
include in bug reports. The better your bug report, the higher the chance that your bug will be
addressed (and possibly fixed) quickly!
5. What happens next?
Once your bug is filed, you will receive email when it is updated at each stage in the bug life
cycle. After the bug is considered fixed, you may be asked to download the latest nightly and
confirm that the fix works for you.
This document describes how to write a good WebKit bug report. Good bug reports help
developers and quality assurance (QA) people decide an appropriate priority and severity for a
bug, and increase the chance that a bug will be fixed quickly. The more specific information you
can provide, the better.
1. Version
Please select the WebKit version you were using when the bug occurred, or the closest
matching version.
Versions of WebKit that are not part of a Safari release have a + after the version number,
and their version number is generally higher then the latest released version of WebKit.
So, for example, 528+ is an unofficial build of WebKit that is newer than the 525.x
version that shipped as part of Safari 3.1.2.
2. Component
If you know the precise cause of a bug (i.e., you've reduced it to a failing test case and
know the reason), then you can assign a bug to a specific component such as CSS or HTML
Editing.
If, however, there is any doubt in your mind as to the cause of the bug, then file it under
New Bugs. This component is the place for any bugs whose cause has not yet been
determined. Once someone has reduced the bug and knows the cause, then it will be
moved from the New Bugs component to the appropriate place.
3. Platform and OS
Please select the platform and the OS version that your bug occurred on. If you're running
on Mac OS X this would often be platform Macintosh and OS Mac OS X 10.5
(Leopard). If you're running on Windows or Linux, please select PC for platform and the
appropriate entry from the OS field. If your exact system is not listed, please select the
closest entry and provide further details in the description of the bug report.
4. Priority
Normally a QA person or developer will set this, so the bug submitter can leave this at
the default value. A number of guidelines and some individual judgment are involved in
setting the priority. If you know the bug is a regression, ie. something is wrong which
wasn't wrong in previous versions of WebKit, you can set this to P1.
5. Severity
In most cases you should leave this at normal, but if you are confident that your bug is
trivial or an enhancement, it's helpful to specify that value. A QA person or developer
will set this to some other value if appropriate.
6. URL
Fill in this field with the URL of a page that shows the bug, when possible. If you have
created a test case reduction for the bug, please add it to the bug report as an attachment
rather than putting it on a web server and listing its URL here. Doing so makes it easier to
work on the bug, and can be a first step towards checking in the test case along with the
bug fix.
7. Summary
A good summary explains the problem in clear and specific terms, but is often concise
enough to fit within the default summary space in Bugzilla. One should be able to tell
exactly what a bug is about just by reading the summary.
o Include the domain of the page that shows the bug (especially if it's an important site)
o If the bug is a crash, note this and note whether or not the crash is reproducible
o If you have tested and verified that this is a regression from a previous version of
WebKit, prepend "REGRESSION: " to the summary
o If you know the range of revisions in which the regression occurred, add this to the
summary after REGRESSION (i.e., "REGRESSION(r31201-r31211):")
8. Description
9. Keywords
If the bug is specific to one or more of the ports of WebKit (Qt, GTK, Wx, etc), please
use any of the valid keywords to tag the bug report accordingly.
10. Depends on
If the fix for this bug depends on another bug fix, put the other bug's number here.
Otherwise, leave it empty.
11. Blocks
If this bug blocks another bug from being fixed, put the other bug's number here.
Otherwise, leave it empty.
WebKit Bugzilla
Bugzilla Keyword Descriptions
Home
| New
| Search
|
Find
| Reports
| Requests
| New Account
| Log In
Open Total
Name Description
Bugs Bugs
Bugs related to the use of the Cairo library
Cairo Search 74
within WebCore
Bugs related to the use of the curl library
Curl Search 36
within WebCore
DeveloperToolsHitList This bug is in the Developer Tools Hitlist Search 23
This bug should be considered for inclusion
DeveloperToolsHitListCandidate Search 1
in the Developer Tools Hitlist
ECMAScript 5 features and compliance
ES5 Search 17
issues.
This bug has been identified as a bug that
EasyFix Search 171
should be easy to fix
Keyword to allow tracking of bugs which
GoogleBug Search 346
concern Google products.
Gtk Bugs related to the Gtk port of WebKit Search 996
HTML5 HTML 5 features and compliance issues. Search 103
This bug has a reduced failing test case
HasReduction Search 1868
attached.
This bug is in the Top 10 Safari
HitList Search 13
Compatibility Bugs Hitlist.
This bug should be considered for the Top
HitListCandidate Search 15
10 List.
The bug is also being tracked in
InChromiumBugs Search 420
Chromium's bug database at .
This bug also has a copy in Apple's Radar
InRadar Search 6176
bug tracker.
For use of the Nokia WebKit guys, to track
InTSW if a bug is in their internal bugtracker, Search 1
TSW.
LayoutTestFailure Bugs which are causing layout test failures Search 571
Bugs that are currently causing the bots to
be red (even intermittently). Once the bug
MakingBotsRed is no longer making bots red (even if the Search 55
underlying bug hasn't been fixed yet), this
keyword should be removed.
NativeListBox NativeListBox bugs Search 35
bug that affect the new popup menu
NativePopUp Search 49
implementation
Regressions from the new text are
NativeTextArea Search 70
implementation.
A keyword to track bugs against the new
NativeTextField Search 132
native form controls in our engine.
Bug that needs a Radar, to help out the
NeedsRadar Search 498
Apple WebKit hackers.
NeedsReduction This bug needs a reduced test case. Search 892
Tracks bugs that need UI work before they
NeedsUI Search 7
can be completed.
Performance This bug relates to a performance issue. Search 110
This bug occurs only on the platform it has
PlatformOnly Search 1196
been reported on.
Qt Bugs related to the Qt port of WebKit Search 2912
Indicates that the Qt bug was triaged
QtTriaged according to the Bug Reporting Guidelines, Search 1405
and passed
This bug is a regression from a previous
Regression Search 2501
version of WebKit.
This bug has been reviewed to determine
ReviewedForRadar whether it needs to be imported into Radar. Search 1132
If it does a NeedsRadar keyword will be
set. When it is later migrated to Radar, the
NeedsRadar keyword will be replaced by
InRadar. Clear the ReviewedForRadar if
you feel a bug should be reconsidered.
Worst SVG Bugs. Any of these could block
SVGHitList SVG from ever being included in an Search 55
official WebKit release.
Bugs about the new implementation of the
SearchField Search 11
search field
Bugs related to the use of the Soup network
Soup Search 33
library in WebCore
Bugs related to the SquirrelFish branch of
SquirrelFish Search 33
JavaScriptCore
Wx Bugs related to the wx port of WebKit. Search 45
XSSAuditor Tasks related to the XSS Auditor. Search 32
YahooBug This bug affects Yahoo products. Search 18
Actions:
o Home
o | New
o | Search
o |
Find
o | Reports
o | Requests
o | New Account
o | Log In
Crash logs are incredibly useful when trying to track down a bug, especially if it's not
immediately reproducible.
Mac OS X
Obtaining a crash log on Mac OS X is incredibly easy since it automatically creates easily
accessible crash logs for you.
1. If WebKit has just crashed or you can easily reproduce the crash, press the Report button
on the CrashReporter dialog box to view the crash information.
2. Copy and paste the entire contents of the top portion of the CrashReporter window into
your favorite text editor and upload it as an attachment in Bugzilla.
3. If the crash report dialog does not appear or the crash is hard to reproduce, crash logs can
be retrieved from the ~/Library/Logs/CrashReporter folder.
On Leopard (Mac OS X 10.5), crash logs are stored as individually dated and time
stamped files. Despite having a “.crash” extension, they are plain text files and can be
attached directly to a bug report.
On Tiger (Mac OS X 10.4), all crashes are logged to Safari.crash.log. This is a plain
text file and can be viewed in the default Console.app or your favorite text editor. All of
Safari's crashes are logged to this file so please only attach the last crash in it. Crashes are
separated by a series of asterisks (∗∗∗∗∗∗∗∗∗∗) for easy identification.
Windows XP
Windows XP does not automatically log crashes like OS X, but it does include Dr. Watson, an
easy to set up tool that can be configured to log them.
1. In the Start menu's Run box or from a DOS or Cygwin prompt, enter the command
drwtsn32 -i.
2. A dialog box will appear informing you that Dr. Watson has been installed as the default
debugger. Press OK.
3. Crash information will now be logged to the user.dmp file in C:\Documents and
Settings\All Users\Application Data\Microsoft\Dr Watson\.
Dr. Watson will create a user.dmp file that records what WebKit was doing when it
crashed. Be careful as it is overwritten with every crash.
When reporting a WebKit bug, please upload the user.dmp file if possible.
4. Running drwtsn32 without any options or switches will bring up a window that allows
you to change various setting such as moving the log folder to a more easily accessible
location or throwing a visual alert letting you know it caught the crash.
Windows Vista
Windows Vista does not include Dr. Watson. Instead, Windows Error Reporting (WER) has
been integrated into the operating system. By default, Vista uploads the crash logs to Microsoft,
but does not save a local copy. This is configurable via the registry.
6. Double-click the file from Windows Explorer and respond affirmatively to any prompts.
7. Reboot
The next time Safari (or any other application) crashes, the crash information will be written into
a folder located inside %LOCALAPPDATA%\Microsoft\Windows\WER\ReportQueue. Check the
modification date to make sure you are using the correct file.
WERxxxx.tmp.mdmp
This is the most important file. It contains the crash dump that can be opened inside Visual
Studio or other Windows debuggers.
WERxxxx.tmp.version.txt
WERxxxx.tmp.appcompat.txt
Lists all of the DLLs loaded at the time of the crash with their version information.
Bugzilla
Creating a Bugzilla account
All you have to do to create a Bugzilla account is enter your email-address and optionally your
real name. You will then receive an email with your password, with which you can login and do
anything you want. Just follow this link: get a Bugzilla account.
Bugzilla "bits"
A "bit" in Bugzilla terms is a setting that allows you to do something. The ones most people
doing a lot with Bugzilla should have are the "canconfirm"-bit and the "editbugs"-bit. You
probably figured out what they do yourself just by their names but i'll explain them anyway.
canconfirm-bit
This bit, when switched on, allows you to confirm bugs of other people when you have
confirmed that the bug they describe is real, moving a bug from UNCONFIRMED to NEW. It
also allows you to file your own bugs as NEW, instead of UNCONFIRMED, which saves you
time when you know for certain that a bug is real.
editbugs-bit
The editbugs bit allows you to edit any part of a bugreport even if you haven't filed the bug
yourself. You can change the title, keywords, component etc. to what you think is best. Having
this bit means you can automatically also confirm bugs.
When you think you have earned the right to have either of these bits switched on for you,
contact us. Do not hesitate to mail the mailing-list or ask on our IRC channel. If you mail the
mailing-list, give us the numbers of a few bugs you filed or bugs you commented on, so we can
check if we think you've earned it too.
Bugzilla
Creating a Bugzilla account
All you have to do to create a Bugzilla account is enter your email-address and optionally your
real name. You will then receive an email with your password, with which you can login and do
anything you want. Just follow this link: get a Bugzilla account.
Bugzilla "bits"
A "bit" in Bugzilla terms is a setting that allows you to do something. The ones most people
doing a lot with Bugzilla should have are the "canconfirm"-bit and the "editbugs"-bit. You
probably figured out what they do yourself just by their names but i'll explain them anyway.
canconfirm-bit
This bit, when switched on, allows you to confirm bugs of other people when you have
confirmed that the bug they describe is real, moving a bug from UNCONFIRMED to NEW. It
also allows you to file your own bugs as NEW, instead of UNCONFIRMED, which saves you
time when you know for certain that a bug is real.
editbugs-bit
The editbugs bit allows you to edit any part of a bugreport even if you haven't filed the bug
yourself. You can change the title, keywords, component etc. to what you think is best. Having
this bit means you can automatically also confirm bugs.
When you think you have earned the right to have either of these bits switched on for you,
contact us. Do not hesitate to mail the mailing-list or ask on our IRC cha
Bug Prioritization
Prioritizing Web Kit Bugs in Bugzilla
This document describes the current guidelines for assigning priorities to Web Kit bugs in
Bugzilla. The relevant bugs are all of those whose product is "WebKit".
Each bug is assigned the first appropriate priority listed below from top to bottom.
P1
P2
P3
P4
All enhancement requests and feature requests not covered the criteria for p1, p2, or p3.
P5
P5 is not used for WebKit bugs. WebKit shares its Bugzilla with other projects who might use it,
that's why it's still there.
The basic idea behind bug reduction is to take a page that demonstrates a problem and remove as
much content as possible while still reproducing the original problem.
A reduced test case can help identify the central problem on the page by eliminating irrelevant
information, i.e., portions of the HTML page’s structure that have nothing to do with the
problem. With a reduced test case, the development team will spend less time identifying the
problem and more time determining the solution. Also, since a site can change its content or
design, the problem may no longer occur on the real-world site. By constructing a test case you
can capture the initial problem.
Really the first step in reducing a page is to identify that main problem of the page. For example:
After you have made this determination, you need to create a local copy of the page created from
the page source window. After saving this source, it’s a good idea to put a <BASE> element in the
HEAD so that any images/external style sheet or scripts that use a relative path will get loaded.
After the BASE element has been added, load the local copy into the browser and verify that
problem is still occurring. In this case, let’s assume the problem is still present.
In general, it’s best to start from the top of the <DOCTYPE> and work down through the HEAD to
the BODY element. Take a look at the HTML file in a text editor and view what types of elements
are present in the <head>. Typically, the HEAD will include the <title> element, which is
required, and elements such as <link>, <style> and <script>.
The reduction process is to remove one element at a time, save, and reload the test case. If you
have removed the element and the page is still displaying the problem, continue with the next
element. If removing an element in the HEAD causes the problem to not occur, you may have
found one piece of the problem. Re-add this element back into the HEAD, reload the page and
confirm the problem is still occurring and move on to the next element in the HEAD.
Once the HEAD element has been reduced, you need to start reducing the number of required
elements in the BODY. This will tend to be the most time consuming since hundreds (thousands)
of elements will be present. The general practice is start removing elements by both their
<start> and </end> elements. This is especially true for tables, which are frequently nested.
You can speed up this process by selecting groups of elements and removing them but ideally
you need to save and reload the test case each time to verify the problem is happening.
Another method
Another way to help you identify unnecessary elements is to temporarily deselect the option
“Enable Javascript” in Safari preferences. If you turn this option off and loading your test case
still reproduces the problem, then any script elements that are present can be removed since they
are not a factor in this issue. Let’s say that you have reduced the page down to a nested table
with an ordered list with an <link> element that need to be present. It’s good practice to identify
that CSS rule that is being in the external file and add it directly to the test case. Create a
<style> </style> in the head and copy/paste the contents of the .css file into this style element.
Remove the <link> and save the changes. Load the test case and verify the problem is still
occurring. Now manually delete or comment out each CSS rule until you have just the required
set of rules to reproduce.
When you’ve finished your reduction, you should add it to the bug. It’s quite likely that in the
process of reducing, you have found the root cause of the problem, so you are able to set the
right component. Don’t forget to add the HasReduction keyword to the bug (and remove the
NeedsReduction keyword, if present). If you do not have the rights to change the component or
the keywords, read about how to get them in this document about Bugzilla.
Ready to begin?
In addition to providing reductions for bugs that you’ve found, you can help by reducing any of
the bugs in Bugzilla tagged with the NeedsReduction keyword.
Bugzilla
Creating a Bugzilla account
All you have to do to create a Bugzilla account is enter your email-address and optionally your
real name. You will then receive an email with your password, with which you can login and do
anything you want. Just follow this link: get a Bugzilla account.
Bugzilla "bits"
A "bit" in Bugzilla terms is a setting that allows you to do something. The ones most people
doing a lot with Bugzilla should have are the "canconfirm"-bit and the "editbugs"-bit. You
probably figured out what they do yourself just by their names but i'll explain them anyway.
canconfirm-bit
This bit, when switched on, allows you to confirm bugs of other people when you have
confirmed that the bug they describe is real, moving a bug from UNCONFIRMED to NEW. It
also allows you to file your own bugs as NEW, instead of UNCONFIRMED, which saves you
time when you know for certain that a bug is real.
editbugs-bit
The editbugs bit allows you to edit any part of a bugreport even if you haven't filed the bug
yourself. You can change the title, keywords, component etc. to what you think is best. Having
this bit means you can automatically also confirm bugs.
When you think you have earned the right to have either of these bits switched on for you,
contact us. Do not hesitate to mail the mailing-list or ask on our IRC channel. If you mail the
mailing-list, give us the numbers of a few bugs you filed or bugs you commented on, so we can
check if we think you've earned it too.
WebKit Bugzilla
Bug List
Home
| New
| Search
|
Find
| Reports
| Requests
| New Account
| Help
| Log In
Actions:
o Home
o | New
o | Search
o |
Find
o | Reports
o | Requests
o | New Account
o | Help
o | Log In
WebKit Bugzilla
Bug 11731: REGRESSION: ASSERTION FAILED: m_webFrame->_private->currentItem
(WebFrameLoaderClient::restoreScrollPositionAndViewState())
Home
| New
| Search
|
Find
| Reports
| Requests
| New Account
| Help
| Log In
Bug List: (1 of 200) |« First Last »| « Prev Next » Show last search results
Bug 11731 - REGRESSION: ASSERTION FAILED: m_webFrame->_private->currentItem
(WebFrameLoaderClient::restoreScrollPositionAndViewState())
REGRESSION: ASSERTION FAILED:
Summary: m_webFrame->_private->currentItem
(WebFrameLoad...
Status: NEW
Product: WebKit
Component: Page Loading
Version: 420+
Macintosh Mac OS X
Platform:
10.4
Importance: P1 Major 2006-11-30 22:09 PST by David Kilzer
Reported:
Assigned (ddkilzer)
Nobody
To: Modified: 2009-05-22 17:57 PST (History)
URL:
InRadar, NeedsReduction,
Keywords:
Regression, ...
Depends on:
Blocks:
Show dependency tree
/ graph
Attachments
Test webarchive (will crash debug builds) (137.54 KB, application/x- no Details
webarchive) flags
2006-11-30 22:11 PST, David Kilzer (ddkilzer)
Test App (48.52 KB, application/octet-stream) no Details
2007-01-18 09:51 PST, David Smith flags
View All Add an attachment (proposed patch, testcase, etc.)
Note
You need to log in before you can comment on or make changes to this bug.
This failure does not occur on the nightly build of r17937 (which is a
release build).
Command: Safari
Path: /Applications/Safari.app/Contents/MacOS/Safari
Parent: bash [442]
PID: 1990
Thread: 0
Thread 0 Crashed:
0 com.apple.WebKit 0x003d6724
WebFrameLoaderClient::restoreScrollPositionAndViewState() + 124
(WebFrameLoaderClient.mm:939)
1 com.apple.WebCore 0x014698a4
WebCore::FrameLoader::checkLoadCompleteForThisFrame() + 1352
(FrameLoaderMac.mm:1020)
2 com.apple.WebCore 0x01493e70
WebCore::FrameLoader::checkLoadComplete() + 204 (FrameLoader.cpp:2150)
3 com.apple.WebCore 0x01496dd0
WebCore::FrameLoader::removeSubresourceLoader(WebCore::ResourceLoader*) + 96
(FrameLoader.cpp:1749)
4 com.apple.WebCore 0x0147502c
WebCore::SubresourceLoader::didFinishLoading() + 384
(SubresourceLoaderMac.mm:174)
5 com.apple.WebCore 0x0146f45c -
[WebCoreResourceLoaderAsDelegate connectionDidFinishLoading:] + 124
(ResourceLoaderMac.mm:571)
6 com.apple.Foundation 0x9299384c -
[NSURLConnection(NSURLConnectionInternal) _sendDidFinishLoadingCallback] +
188
7 com.apple.Foundation 0x92991ab8 -
[NSURLConnection(NSURLConnectionInternal) _sendCallbacks] + 556
8 com.apple.Foundation 0x92991810 _sendCallbacks + 156
9 com.apple.CoreFoundation 0x907dd4cc __CFRunLoopDoSources0 + 384
10 com.apple.CoreFoundation 0x907dc9fc __CFRunLoopRun + 452
11 com.apple.CoreFoundation 0x907dc47c CFRunLoopRunSpecific + 268
12 com.apple.HIToolbox 0x93208740 RunCurrentEventLoopInMode +
264
13 com.apple.HIToolbox 0x93207dd4 ReceiveNextEventCommon +
380
14 com.apple.HIToolbox 0x93207c40
BlockUntilNextEventMatchingListInMode + 96
15 com.apple.AppKit 0x9370bae4 _DPSNextEvent + 384
16 com.apple.AppKit 0x9370b7a8 -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:] + 116
17 com.apple.Safari 0x00006740 0x1000 + 22336
18 com.apple.AppKit 0x93707cec -[NSApplication run] + 472
19 com.apple.AppKit 0x937f887c NSApplicationMain + 452
20 com.apple.Safari 0x0005c77c 0x1000 + 374652
21 com.apple.Safari 0x0005c624 0x1000 + 374308
------- Comment #1 From David Kilzer (ddkilzer) 2006-11-30 22:11:02 PST -------
Created an attachment (id=11702) [details]
Test webarchive (will crash debug builds)
This attachment is a tiny app that demonstrates the crash. It just loads an
empty html file, and then when you click reload (attached to -reload:) it
will crash. The executable is set to use the webkit from a nightly in
/Applications.
------- Comment #3 From mitz@webkit.org 2007-01-18 14:05:31 PST -------
According to David Smith, this crashes in release builds.
------- Comment #4 From Brady Eidson 2007-01-18 15:15:57 PST -------
I can totally repro this using the test app.
I don't have alot of time to look at it at the moment, but this is high on my
priority list.
It's quite easy to see from the assertion that it'll crash a release build,
as well ;) Every single time!
------- Comment #5 From Mark Rowe (bdash) 2007-01-18 16:38:18 PST -------
<rdar://problem/4940408>
------- Comment #6 From Joost de Valk (AlthA) 2007-01-19 06:45:08 PST -------
If this crashes release builds as well, this isn't a regression now is it? :)
------- Comment #7 From mitz@webkit.org 2007-01-19 06:49:12 PST -------
(In reply to comment #6)
> If this crashes release builds as well, this isn't a regression now is it?
:)
>
"release builds" in this context means "TOT builds using the release build
style", not "shipping builds".
------- Comment #8 From mitz@webkit.org 2007-02-14 13:09:49 PST -------
I could not reproduce the bug with the test app, although it's still
reproducible with the webarchive.
------- Comment #9 From Anders Carlsson 2007-03-12 11:59:56 PST -------
This regressed in http://trac.webkit.org/projects/webkit/changeset/14920
------- Comment #10 From Alexey Proskuryakov 2007-04-29 00:07:31 PST -------
The attached webarchive doesn't crash nightly r21059 for me. A comment after
the failing assertion casts some doubt over its validity:
Bug List: (1 of 200) |« First Last »| « Prev Next » Show last search results
Actions:
o Home
o | New
o | Search
o |
Find
o | Reports
o | Requests
o | New Account
o | Help
o | Log In
This document describes the life cycle of a bug in the WebKit open-source project. In most ways
this is the same as the life cycle of a bug in any Bugzilla project. The Bugzilla site also includes
more details about the life cycle of Bugzilla bugs.
Fresh, Unconfirmed Bugs
A freshly-created bug starts out in state UNCONFIRMED. Often it is in component New Bugs, but
some bugs will be given an initial component in the initial bug-reporting step.
Confirming Bugs
The next step is for someone with Bugzilla canConfirm privileges to review the unconfirmed
bug and decide whether it has enough useful information to move forward. The possible changes
to the bug at this step include the following:
Resolution changed to DUPLICATE if the bug is determined to have the same cause as a bug
reported earlier.
Resolution changed to WORKSFORME if the bug seems to not be present in the latest sources.
Resolution changed to INVALID if the bug does not describe a problem with WebKit.
Resolution changed to WONTFIX in the rare case that the bug seems valid but there's a specific
reason why it should not be fixed in WebKit (usually this would be a cross-browser compatibility
issue).
Comments/questions added if the bug does not have enough information to move forward.
Status changed to NEW if the bug is reproducible with the latest sources on Mac OS X or
otherwise has enough information to move forward. If the bug is not reproducible with the
latest sources, but appears to occur only on the platform stated in the platform field, the
PlatformOnly keyword is added as well as setting the status to NEW. Along with changing the
status, the component should also be set to an appropriate one more specific than New Bugs if
necessary.
Analyzing Bugs
Each bug is initially assigned to the person designated as owner of the component. The assignee
should move the bug from status NEW to status ASSIGNED after they have read the bug and are
satisfied that it represents a real problem in WebKit. If they are not satisfied about this, they
should perform one of the actions mentioned in the Confirming Bugs section above. The same
procedure is followed for bugs with status REOPENED (see Verifying Fixes below).
The assignee represents the person who is expected to take the next step in investigating or fixing
a bug. If someone other than the assignee is investigating or fixing a bug, the assignee should be
changed to the person doing the work. This helps prevent duplicated work. It's always helpful to
add a comment explaining why an assignee has been changed.
Proposing Fixes
A proposed patch should be added as a new attachment. The attachment should have the patch
checkbox checked, and the review flag set to ?. This marks the patch as awaiting review. If the
patch requires the specialized knowledge of a particular reviewer, the submitter or another
reviewer should put the requested reviewer's email address in the Requestee field. Otherwise
this field should be left empty. The state is left at ASSIGNED at this point; it isn't changed to
FIXED until a fix has been checked into the source tree.
When the review flag's state is changed, or when a comment is made in the Edit form for an
attachment, email is automatically sent to the webkit-reviews mailing list. The reviewers all
subscribe to this list, and anyone else is free to do so as well.
If the submitter of a patch changes their mind about wanting a review, they should clear the
review flag by choosing the blank choice in the review pop-menu.
More details about how to prepare code changes can be found elsewhere on this site.
A reviewer will read through each proposed patch. If the patch is ready to commit, the reviewer
will change the review flag to +. For clarity, it's helpful for the reviewer to add a comment when
approving a patch. Often this comment is just "r=me", which is simply shorthand for "I have
reviewed this patch and it's ready to commit".
A patch might not be ready to commit for various reasons. The bug fix might be incorrect. The
test cases included in the patch might be insufficient. The bug fix and test cases might be fine but
the coding style might be incorrect. The reviewer should always explain in detail why a patch is
not ready to commit, so the submitter or someone else can revise the patch.
When a submitter proposes an updated patch, they should check the obsolete checkbox on the
previous version of the patch. This causes it to appear crossed-out in the list of attachments on
the bug's main page. At the same time as marking the old patch obsolete, the submitter should
also clear the review flag. This would happen automatically in a perfect world, but doesn't
currently in this one.
Committing Patches
After a patch has been approved, someone with commit privileges in the WebKit source
repository will commit the patch into the source code repository. The committer should change
the state of the bug to FIXED; generally the assignee is left unchanged at this point.
All of the people with commit privileges should be subscribed to the webkit-reviews mailing list,
and so they will receive email when a patch is approved and thus ready to be committed. If an
approved patch has not been committed for what seems to be an inordinately long time, the patch
submitter could send email requesting status to this mailing list. As a last resort, the patch
submitter could contact the reviewer directly. Due to everyone's busy schedules, some delays in
getting patches reviewed, and then in getting them committed, are inevitable.
If the bug report mentions that the same bug is represented in another internal system, such as
Apple's internal Radar system, and the person who commits the bug has access to that system,
then the person who commits the bug should also change the state of the bug appropriately in the
internal system. For a Radar bug the new appropriate state would be Software
Changed/Integrate.
Verifying Fixes
After the patch for a bug has been committed, the fix still needs to be verified. Typically this step
is done by the person who originally submitted the bug report. If the submitter is not available or
does not feel that they can verify the fix, the verification step can be done by anyone with bug
editing privileges who is familiar enough with the originally reported problem to be confident
about testing it. Note that once a bug is in the FIXED state, the assignee can no longer be
changed. This means that a bug that needs to be verified will not usually be assigned to the
person expected to verify the bug.
To verify a bug fix, build and run the sources that include the fix, and check whether the
originally reported problem still occurs. If the problem no longer occurs, change the resolution to
VERIFIED. If the problem does still occur, change the resolution to REOPENED and assign it to the
person who submitted the patch.
Closing Bugs
Fixed bugs have the VERIFIED resolution until a version of WebKit that includes the fix has been
publicly released. At this point, the resolution is changed to CLOSED.
A layout test is simply a web page. The layout test machinery renders the web page, and then
dumps the internal representation, the render tree, with details of the layout. This lets engineers
working on the project know if they do anything that changes the layout. Once we get a test
rendering properly, we check it in as part of the layout test suite.
The following are some guidelines to follow when writing new layout tests:
1. The test should be the smallest possible code fragment that tests the feature.
2. The test should fit on one page (unless of course it’s testing scrolling).
3. The test should clearly describe what feature it is testing.
4. The test should clearly describe the expected result. It should be possible through visual
inspection alone to determine that the test has failed.
A layout test should work both in the browser itself, and in the layout test tool. The layout test
tool provides an additional object on the window object called the layout test controller with
some methods that control test output. One you should know about is the
layoutTestController.dumpAsText method. Calling this from JavaScript within a test
arranges for the output to be written out as plain text rather than as a render tree dump. This is
useful for tests that are testing something other than layout. The event creation test mentioned
above is a good example of how to do this and when it makes sense.
Some tests require pixel-level comparisons. For these tests, you must generate expected output
for a specific machine type, operating system, and color profile. When you add such a test, you
can generate new expected output automatically using the run-webkit-tests --pixel
command. This will automatically configure the color profile, and place the resulting rendered
image (and checksum) in the appropriate platform directory for checkin.
The Ahem font is useful in testing text layout, since its glyphs’ metrics are well known, and it is
always available to tests running in the layout test tool. However, if you want to view tests that
use Ahem in Safari, you should download Ahem, open it in the Font Book application, and click
on the Install Font button to install it.
The CSS working group has an excellent document on test writing guidelines for CSS tests. This
wiki article has more information on writing good tests and the DumpRenderTree tool.
Elika J. Etemad
Copyright © 2003 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark,
document use and software licensing rules apply.
Abstract
This is a supporting document for authors of tests in the CSS2.1 test suite. It describes the key
aspects of CSS tests, and gives various techniques authors should use when writing tests.
These guidelines were produced by members of the CSS working group which is part of the style
activity (see summary).
Comments on, and discussions of this document can be sent on the (archived) public mailing list
public-css-testsuite@w3.org (see instructions). W3C Members can also send comments directly
to the CSS working group.
These guidelines represent the current thinking of the working group and as such may be
updated, replaced or rendered obsolete by other W3C documents at any time. Its publication does
not imply endorsement by the W3C membership or the CSS Working Group (members only).
Patent disclosures relevant to CSS may be found on the Working Group's public patent
disclosure page.
Table of contents
1. Introduction
2. Key aspects of tests
o 2.1. Easy to determine the result
o 2.2. Quick to determine the result
o 2.3. Self explanatory
o 2.4. Short
o 2.5. Valid
o 2.6. Cross-platform
3. Format
o 3.1. Kinds of test
o 3.2. Links to the specification
o 3.3. Recommended content
o 3.4. Content-Style-Type and Content-Script-Type
o 3.5. Encoding
o 3.6. Special cases
o 3.7. Filenames
4. Writing ideal tests
o 4.1. Indicating success
4.1.1. The green paragraph
4.1.2. The green page
4.1.3. The green block
4.1.4. The green paragraph and the blank page
4.1.5. The two identical renderings
4.1.6. The positioned text
o 4.2. Indicating failure
4.2.1. Red
4.2.2. Overlapped text
4.2.3. The word "FAIL"
4.2.4. Scrambled text
o 4.3. Techniques
4.3.1. Overlapping
4.3.2. Special fonts
4.3.3. The self explanatory sentence followed by pages of identical text
4.3.4. Color
4.3.5. Methodical testing
o4.4. Tests to avoid
4.4.1. The long test
4.4.2. The counterintuitive "this should be red" test
4.4.3. Unobvious tests
Acknowledgments
References
o Normative references
o Other references
Index
1. Introduction
This document explains how to write test cases for the CSS2.1 test suite.
A badly written test can lead to the tester not noticing a failure, as well as breaking the tester's
concentration. Therefore it is important that the tests all be of a high standard.
Tests are viewed one after the other in quick succession, usually in groups of several hundred to
a thousand. As such, it is important that the results be easy to interpret.
The tests should need no more than a few seconds to convey their results to the tester.
2.4. Short
Tests should be very short (a paragraph or so) and certainly not require scrolling on even the
most modest of screens, unless the test is specifically for scrolling or paginating behaviour.
2.5. Valid
Unless specifically testing error-recovery features, the tests should all be valid.
2.6. Cross-platform
Test should be as cross-platform as reasonably possible, working across different devices, screen
resolutions, paper sizes, etc. Exceptions should document their assumptions.
3. Format
basic cases
tests that check the simple (but realistic) aspects of a feature, for example the various named
color values, or inheritance of a property
composite cases
tests that check combinations of features, for example 'border-top-color' with 'color'.
edge cases
failure cases
tests that check failure conditions and error-handling. (These tests are likely to involve invalid
CSS2.1 stylesheets.)
scenario cases
tests that combine multiple features into one complex scenario (Acid 2 is an example of a
scenario case, albeit one also that tests features outside the scope of the CSS specs)
3.2. Links to the specification
Each test will contain one or more links to the relevant part of the specification:
The first of these links will decide the position of the test in the test suite. The links will be
ordered from rare to common such that the link to the rarest feature will be first.
The URIs will point to the /TR/CSS21/ spec (i.e. the "latest version"), not to the version existing
at the time of publication.
Basic and failure tests should limit themselves to <p>, <div>, <img>, and <span> elements.
Other tests checking for the interaction of CSS with other XHTML elements, or elements from
other namespaces, may include those other elements too.
If possible without compromising the test itself, block-level markup should be indented to show
the structure of the document, as in the template given above.
When the document contains inline style attributes, then the following line should be added
immediately after the title element in the markup:
When the document contains inline script (event handler) attributes, then the following line
should be added immediately after the title element in the markup:
3.5. Encoding
Tests should use UTF-8 unless the test is specifically checking encoding handling. If the
XHTML 1.1 source files need to define a character set other than UTF-8 or UTF-16, then they
will define their character set using an XML declaration, as in:
<?xml encoding="iso-8859-1"?/>
3.6. Special cases
It is expected that there will be special cases, e.g. tests that check for the cascading order of
multiple stylesheets. Those tests will be handled on a case-by-case basis. Support files will all be
kept in one support directory, if possible.
3.7. Filenames
test-topic-###.ext
test-topic
A short identifier that describes the test. The test-topic should avoid conjunctions, articles,
and prepositions. It is a filename, not an English phrase: it should be as concise as possible.
###
This is a zero-filled number used to keep the filenames unique when files have the same test-
topic name. For example in the case of margin-collapsing there are multiple cases so each case
could have the same test-topic but different numbers.
ext
The file extension or format of the file, usually xht (for XHTML).
Well designed CSS tests typically fall into several categories, named after the features that the
test will have when correctly rendered by a user agent.
Note: The terms "the test has passed" and "the test has failed" refer to whether the user agent has
passed or failed a particular test — a test can pass in one web browser and fail in another. In
general, the language "the test has passed" is used when it is clear from context that a particular
user agent is being tested, and the term "this-or-that-user-agent has passed the test" is used when
multiple user agents are being compared.
This is the simplest form of test, and is most often used when testing the parts of CSS that are
independent of the rendering, like the cascade or selectors. Such tests consist of a single line of
text describing the pass condition, which will be one of the following:
Examples:
http://www.hixie.ch/tests/adhoc/css/box/inline/002.html
http://www.hixie.ch/tests/adhoc/css/background/20.xml
This is a variant on the green paragraph test. There are certain parts of CSS that will affect the
entire page, when testing these this category of test may be used. Care has to be taken when
writing tests like this that the test will not result in a single green paragraph if it fails. This is
usually done by forcing the short descriptive paragraph to have a neutral color (e.g. white).
Example:
http://www.hixie.ch/tests/adhoc/css/background/18.xml
(This example is poorly designed, because it does not look red when it has failed.)
This is the best type of test for cases where a particular rendering rule is being tested. The test
usually consists of two boxes of some kind that are (through the use of positioning, negative
margins, zero line height, or other mechanisms) carefully placed over each other. The bottom
box is colored red, and the top box is colored green. Should the top box be misplaced by a faulty
user agent, it will cause the red to be shown. (These tests sometimes come in pairs, one checking
that the first box is no bigger than the second, and the other checking the reverse.)
Examples:
http://www.hixie.ch/tests/adhoc/css/box/absolute/001.xml
http://www.hixie.ch/tests/adhoc/css/box/table/010.xml
These tests appear to be identical to the green paragraph tests mentioned above. In reality,
however, they actually have more in common with the green block tests, but with the green block
colored white instead. This type of test is used when the displacement that could be expected in
the case of failure is likely to be very small, and so any red must be made as obvious as possible.
Because of this, test would appear totally blank when the test has passed. This is a problem
because a blank page is the symptom of a badly handled network error. For this reason, a single
line of green text is added to the top of the test, reading something like:
This line should be green and there should be no red on this page.
Example:
http://www.hixie.ch/tests/adhoc/css/fonts/size/002.xml
It is often hard to make a test that is purely green when the test passes and visibly red when the
test fails. For these cases, it may be easier to make a particular pattern using the feature that is
being tested, and then have a reference rendering next to the test showing exactly what the test
should look like.
The reference rendering could be either an image, in the case where the rendering should be
identical, to the pixel, on any machine, or the same pattern made using totally different parts of
the CSS specification. (Doing the second has the advantage of making the test a test of both the
feature under test and the features used to make the reference rendering.)
Examples:
http://www.hixie.ch/tests/adhoc/css/box/block/003.html
http://www.hixie.ch/tests/adhoc/css/box/table/003.html
http://www.hixie.ch/tests/adhoc/css/box/ib/002.xml
There are some cases where the easiest test to write is one where the four letters of the word
'PASS' are individually positioned on the page. This type of test is then said to have passed when
all that can be seen is the word with all its letters aligned. Should the test fail, the letters are
likely to go out of alignment, for instance:
PA
SS
...or:
SSPA
The problem with this test is that when there is a failure it is sometimes not immediately clear
that the rendering is wrong. (e.g. the first example above could be thought to be intentional.)
Example:
http://www.hixie.ch/tests/adhoc/css/box/block/text-indent/001.html
Ideal tests, as well as having well defined characteristics when they pass, should have some clear
signs when they fail. It can sometimes be hard to make a test do something only when the test
fails, because it is very hard to predict how user agents will fail! Furthermore, in a rather ironic
twist, the best tests are those that catch the most unpredictable failures!
Having said that, here are the best ways to indicate failures:
4.2.1. Red
This is probably the best way of highlighting bugs. Tests should be designed so that if the
rendering is a few pixels off some red is uncovered.
Examples:
http://www.hixie.ch/tests/adhoc/css/box/block/first-line/001.html
Tests of the 'line-height', 'font-size' and similar properties can sometimes be devised in such a
way that a failure will result in the text overlapping.
Some properties lend themselves well to this kind of test, for example 'quotes' and 'content'. The
idea is that if the word "FAIL" appears anywhere, something must have gone wrong.
Examples:
http://www.hixie.ch/tests/adhoc/css/box/table/004.html
http://www.hixie.ch/tests/adhoc/css/box/absolute/002.xml
This is similar to using the word "FAIL", except that instead of (or in addition to) having the
word "FAIL" appear when an error is made, the rest of the text in the test is generated using the
property being tested. That way, if anything goes wrong, it is immediately obvious.
Examples:
http://www.hixie.ch/tests/adhoc/css/quotes/001.xml
These are in addition to those inherent to the various test types, e.g., differences in the two halves
of a two identical renderings test obviously also shows a bug.
4.3. Techniques
In addition to the techniques mentioned in the previous sections, there are some techniques that
are important to consider or to underscore.
4.3.1. Overlapping
This technique should not be cast aside as a curiosity -- it is in fact one of the most useful
techniques for testing CSS, especially for areas like positioning and the table model.
The basic idea is that a red box is first placed using one set of properties, e.g. the block box
model's margin, height and width properties, and then a second box, green, is placed on top of
the red one using a different set of properties, e.g. using absolute positioning.
This idea can be extended to any kind of overlapping, for example overlapping to lines of
identical text of different colors.
Todd Fahrner has developed a font called Ahem, which consists of some very well defined
glyphs of precise sizes and shapes. This font is especially useful for testing font and text
properties. Without this font it would be very hard to use the overlapping technique with text.
Examples:
http://www.hixie.ch/tests/adhoc/css/fonts/ahem/001.xml
http://www.hixie.ch/tests/adhoc/css/fonts/ahem/002.xml
The font's em-square is exactly square. It's ascent and descent is exactly the size of the em
square. This means that the font's extent is exactly the same as its line-height, meaning that it can
be exactly aligned with padding, borders, margins, and so forth.
The font's alphabetic baseline is 0.2em above its bottom, and 0.8em below its top.
A rectangle exactly 0.2em high, 1em wide, and aligned so that its top is flush with the
p U+0070
baseline.
A rectangle exactly 0.8em high, 1em wide, and aligned so that its bottom is flush with the
É U+00C9
baseline.
Most other US-ASCII characters in the font have the same glyph as X.
4.3.3. The self explanatory sentence followed by pages of identical text
For tests that must be long (e.g. scrolling tests), it is important to make it clear that the filler text
is not relevant, otherwise the tester may think he is missing something and therefore waste time
reading the filler text. Good text for use in these situations is, quite simply, "This is filler text.
This is filler text. This is filler text.". If it looks boring, it's working!
4.3.4. Color
Red
Green
Blue
Tests that do not use red or green to indicate success or failure should use blue to indicate that
the tester should read the text carefully to determine the pass conditions.
Black
These are useful colors when making complicated patterns for tests of the two identical
renderings type.
Gray
Descriptive lines, such as borders around nested boxes, are usually dark gray. These lines come
in useful when trying to reduce the test for engineers.
Silver
Light gray is sometimes used for filler text to indicate that it is irrelevant.
http://www.hixie.ch/tests/adhoc/css/fonts/size/004.xml
4.3.5. Methodical testing
There are particular parts of CSS that can be tested quite thoroughly with a very methodical
approach. For example, testing that all the length units work for each property taking lengths is
relatively easy, and can be done methodically simply by creating a test for each property/unit
combination.
In practice, the important thing to decide is when to be methodical and when to simply test, in an
ad hoc fashion, a cross section of the possibilities.
This example is a methodical test of the :not() pseudo-class with each attribute selector in turn,
first for long values and then for short values:
http://www.hixie.ch/tests/adhoc/css/selectors/not/010.xml
Any manual test that is so long that is needs to be scrolled to be completed is too long. The
reason for this becomes obvious when you consider how manual tests will be run. Typically, the
tester will be running a program (such as "Loaderman") which cycles through a list of several
hundred tests. Whenever a failure is detected, the tester will do something (such as hit a key) that
takes a note of the test case name. Each test will be on the screen for about two or three seconds.
If the tester has to scroll the page, that means he has to stop the test to do so.
Of course, there are exceptions -- the most obvious one being any tests that examine the scrolling
mechanism! However, these tests are considered tests of user interaction and are not run with the
majority of the tests.
In general, any test that is so long that it needs scrolling can be split into several smaller tests, so
in practice this isn't much of a problem.
http://www.bath.ac.uk/~py8ieh/internet/eviltests/lineheight3.html
As mentioned many times in this document, red indicates a bug, so nothing should ever be red in
a test.
There is one important exception to this rule... the test for the 'red' value for the color properties!
A test that has half a sentence of normal text with the second half bold if the test has passed is
not very obvious, even if the sentence in question explains what should happen.
There are various ways to avoid this kind of test, but no general rule can be given since the
affected tests are so varied.
http://www.w3.org/Style/CSS/Test/current/sec525.htm
Acknowledgments
[acknowledgments]
References
Normative references
Other references
Index
Contributing Code
This page describes how to contribute changes to the WebKit source control repository. The
WebKit project maintains several scripts to assist you. This page assumes you already know how
to check out and build the code.
Overview
Below are the recommended steps. Later sections of this page explain each step in more detail.
The bugs.webkit.org database is the central point of communication for contributions to WebKit.
Nearly every contribution corresponds to a bug report there. Note that WebKit uses bug reports
to track all types of code changes and not just bug fixes.
Choose a bug report to work on. You can also create a new report. Be sure to search the database
before creating new reports to avoid duplication.
After choosing a bug report, follow the WebKit bug life cycle guidelines for the report. For
example, it is often good practice to comment in a report if you are working on that issue. If your
change may be controversial, you may want to check in advance with the webkit-dev mailing
list.
If you make substantive changes to a file, you may wish to add a copyright line for yourself or
for the company on whose behalf you work. Below are sample copyright lines for an individual
contributor and a company:
In addition, make sure that any new source code and script files you introduce contain license
text at the beginning of the file. If you are the author of a new file, preferred license text to
include can be found here: WebKit/LICENSE. (The "Original Format" link at the bottom of the
page contains text that can be cut and pasted more easily.) Simply replace the copyright line with
your own information, for example as suggested above.
Patches must comply with the code style guidelines. Some older parts of the codebase do not
follow these guidelines. If you are modifying such code, it is generally best to clean it up to
comply with the current guidelines. An exception is legacy components, which should not be
cleaned up.
Regression tests
Once you have made your changes, you need to run the regression tests, which is done via the
run-webkit-tests script. All tests must pass. Patches will not be landed in the tree if they break
existing layout tests.
For any feature that affects the layout engine, a new regression test must be constructed. If you
provide a patch that fixes a bug, that patch should also include the addition of a regression test
that would fail without the patch and succeed with the patch. If no regression test is provided, the
reviewer will ask you to revise the patch, so you can save time by constructing the test up front
and making sure it's attached to the bug. If no layout test can be (or needs to be) constructed for
the fix, you must explain why a new test isn't necessary to the reviewer.
Information on writing a layout test as well as what needs to be done if you've made changes to
JavaScriptCore can be found on the testing page.
If your changes include adding new files (like new layout tests), use the svn add command to
mark these files for addition to the repository. If you do not do this, the new files will be missing
from the patch file you generate below.
You can learn more about Subversion commands like svn add from the online book Version
Control with Subversion and by using the svn help command.
ChangeLog files
ChangeLogs are simple text files which provide historical documentation for all changes to the
WebKit project. All patches require an entry to the ChangeLog. The prepare-ChangeLog script
will create a basic entry containing a list of all files that have been changed. The first line
contains the date, your full name, and your email address. Use this to write up a brief summary
of the changes you've made. Don't worry about the "Reviewed by NOBODY (OOPS!)" line, the
person landing your patch will fill this in.
There is one ChangeLog per top-level directory, if you changed code and tests you will need to
edit at least two ChangeLogs. The prepare-ChangeLog script will create a stub entries for you.
You should edit these stubs to describe your change, including the full url to the bug (example
entry, note that you can use --bug flag). (You should set EMAIL_ADDRESS and
CHANGE_LOG_NAME in your environment if you will be running this script frequently.)
The "No new tests. (OOPS!)" line appears if prepare-ChangeLog did not detect the addition of
test cases. If your patch does not require test cases (or test cases are not possible), you should
include a line stating such. Otherwise all changes require test cases which should be mentioned
in the ChangeLog.
Create the patch
The svn-create-patch script does not create a file automatically. You need to redirect the
output yourself using something like:
Submit your patch by clicking the "Add an attachment" link in the bug report you chose for your
contribution.
The patch checkbox and the review:? flag signal to WebKit reviewers that your patch is ready
for review. Setting the review flag also sends an automatic e-mail to the webkit-reviews mailing
list which some reviewers subscribe to.
Respond to reviewers
A WebKit reviewer must approve your patch before WebKit can accept it into the source control
repository. A reviewer will typically either approve your patch (by responding with an r=me in
the bug report and marking the patch review:+) or request revisions to your patch (and mark the
patch review:-). In rare cases a patch may be permanently rejected, meaning that the reviewer
believes the feature should never be committed to the tree. The review process can consist of
multiple iterations between you and the reviewer as you submit revised patches.
Once a patch is approved, you should ask someone with commit access to land your patch.
Alternatively you can request that your patch be committed by our commit bot.
In either case, your responsibility for the patch does not end with the patch landing in the tree.
There may be regressions from your change or additional feedback from reviewers after the
patch has landed. You can watch the tree at build.webkit.org to make sure your patch builds and
passes tests on all platforms. It is your responsibility to be available should regressions arise and
to respond to additional feedback that happens after a check-in.
Changes should succeed on all platforms, but it can be difficult to test on every platform WebKit
supports. Be certain that your change does not introduce new test failures on the high-traffic Mac
or Windows ports by comparing the list of failing tests before and after your change. Your
change must at least compile on all platforms.
WebKit provides an automated system (commit-queue) for landing patches for any who would
like to use it. To use the commit-queue, set the commit-queue:? flag on your patch. A
committer will set commit-queue:+ and an automated process will download, build, run the
layout tests, and submit your patch on your behalf. If the WebKit buildbots are passing, your
patch should be landed within 15 minutes after commit-queue:+ is set. See the commit-queue
documentation for more information.
Our Committer and Reviewer policy provides details on obtaining commit and review privileges.
WebKit Scripts
The WebKit project maintains several scripts to assist with things like building and testing code,
checking style, and preparing patches.
The Tools/Scripts folder of the WebKit source tree contains these scripts. In fact, unless
otherwise mentioned, all of the scripts mentioned on this site are located in this folder.
Running a script
To run the build-webkit script, for example, type the following from the command line:
WebKit/Tools/Scripts/build-webkit
Similarly, to run the build-webkit script with the --help option, type the following:
WebKit/Tools/Scripts/build-webkit --help
It is convenient to add WebKit/Tools/Scripts to your shell path so you can run WebKit scripts
without typing the full path.
For example, this will allow you to type the following for the two examples above:
build-webkit
build-webkit --help
The instructions throughout this site assume you have added WebKit/Tools/Scripts to your
shell path. If you do not add this directory to your shell path, simply always include the full path
as in the first examples above.
Getting WebKit
To download a pre-built bundle containing the latest WebKit, visit WebKit Nightly Builds.
Checking Out
To work with the WebKit source tree, you will need a Subversion client installed. See Installing
Developer Tools for information on how to install Subversion.
Mac OS X
2. Open Terminal
Windows
Alternatively you can download a snapshot of the WebKit source tree from
http://nightly.webkit.org/files/WebKit-SVN-source.tar.bz2. It is updated every six hours.
Windows
Download the WebKit Support Libraries to the root of your source tree
(C:\cygwin\home\<username>\WebKit).
If you downloaded the tarball, this will bring it up to date. Windows users must always
execute this command after first obtaining the code, since it will download additional
libraries that are needed to build.
Once you have a current tree, the next step is building WebKit.
Keeping up to Date
At any time, you can rerun the update-webkit script to update your source tree.
Building WebKit
Building WebKit requires that you have the proper developer tools installed and that you have a copy of
the WebKit source tree.
Windows
1. Open a Cygwin Shell (if not already open from checking out sources)
Use the --debug option for a debug build, which includes debugging symbols and
assertions:
build-webkit --debug
Windows
A common source of build errors on Windows is Visual C++ Express forgetting the Platform
SDK paths. If you have trouble building WebKit, double check that the paths you set during step
2 of the Platform SDK Installation are still there and add them again if necessary.
Don't forget that if you have any questions or problems building WebKit, feel free to get in
touch!
Once your build has finished, you can run it inside Safari.
1. To set a default build configuration for build-webkit and other scripts, use the set-
webkit-configuration script:
set-webkit-configuration --debug
set-webkit-configuration --release
Contributing Code
This page describes how to contribute changes to the WebKit source control repository. The
WebKit project maintains several scripts to assist you. This page assumes you already know how
to check out and build the code.
Overview
Below are the recommended steps. Later sections of this page explain each step in more detail.
The bugs.webkit.org database is the central point of communication for contributions to WebKit.
Nearly every contribution corresponds to a bug report there. Note that WebKit uses bug reports
to track all types of code changes and not just bug fixes.
Choose a bug report to work on. You can also create a new report. Be sure to search the database
before creating new reports to avoid duplication.
After choosing a bug report, follow the WebKit bug life cycle guidelines for the report. For
example, it is often good practice to comment in a report if you are working on that issue. If your
change may be controversial, you may want to check in advance with the webkit-dev mailing
list.
Develop your changes
If you make substantive changes to a file, you may wish to add a copyright line for yourself or
for the company on whose behalf you work. Below are sample copyright lines for an individual
contributor and a company:
In addition, make sure that any new source code and script files you introduce contain license
text at the beginning of the file. If you are the author of a new file, preferred license text to
include can be found here: WebKit/LICENSE. (The "Original Format" link at the bottom of the
page contains text that can be cut and pasted more easily.) Simply replace the copyright line with
your own information, for example as suggested above.
Patches must comply with the code style guidelines. Some older parts of the codebase do not
follow these guidelines. If you are modifying such code, it is generally best to clean it up to
comply with the current guidelines. An exception is legacy components, which should not be
cleaned up.
Regression tests
Once you have made your changes, you need to run the regression tests, which is done via the
run-webkit-tests script. All tests must pass. Patches will not be landed in the tree if they break
existing layout tests.
For any feature that affects the layout engine, a new regression test must be constructed. If you
provide a patch that fixes a bug, that patch should also include the addition of a regression test
that would fail without the patch and succeed with the patch. If no regression test is provided, the
reviewer will ask you to revise the patch, so you can save time by constructing the test up front
and making sure it's attached to the bug. If no layout test can be (or needs to be) constructed for
the fix, you must explain why a new test isn't necessary to the reviewer.
Information on writing a layout test as well as what needs to be done if you've made changes to
JavaScriptCore can be found on the testing page.
If your changes include adding new files (like new layout tests), use the svn add command to
mark these files for addition to the repository. If you do not do this, the new files will be missing
from the patch file you generate below.
You can learn more about Subversion commands like svn add from the online book Version
Control with Subversion and by using the svn help command.
ChangeLog files
ChangeLogs are simple text files which provide historical documentation for all changes to the
WebKit project. All patches require an entry to the ChangeLog. The prepare-ChangeLog script
will create a basic entry containing a list of all files that have been changed. The first line
contains the date, your full name, and your email address. Use this to write up a brief summary
of the changes you've made. Don't worry about the "Reviewed by NOBODY (OOPS!)" line, the
person landing your patch will fill this in.
There is one ChangeLog per top-level directory, if you changed code and tests you will need to
edit at least two ChangeLogs. The prepare-ChangeLog script will create a stub entries for you.
You should edit these stubs to describe your change, including the full url to the bug (example
entry, note that you can use --bug flag). (You should set EMAIL_ADDRESS and
CHANGE_LOG_NAME in your environment if you will be running this script frequently.)
The "No new tests. (OOPS!)" line appears if prepare-ChangeLog did not detect the addition of
test cases. If your patch does not require test cases (or test cases are not possible), you should
include a line stating such. Otherwise all changes require test cases which should be mentioned
in the ChangeLog.
The svn-create-patch script does not create a file automatically. You need to redirect the
output yourself using something like:
Submit your patch by clicking the "Add an attachment" link in the bug report you chose for your
contribution.
The patch checkbox and the review:? flag signal to WebKit reviewers that your patch is ready
for review. Setting the review flag also sends an automatic e-mail to the webkit-reviews mailing
list which some reviewers subscribe to.
Respond to reviewers
A WebKit reviewer must approve your patch before WebKit can accept it into the source control
repository. A reviewer will typically either approve your patch (by responding with an r=me in
the bug report and marking the patch review:+) or request revisions to your patch (and mark the
patch review:-). In rare cases a patch may be permanently rejected, meaning that the reviewer
believes the feature should never be committed to the tree. The review process can consist of
multiple iterations between you and the reviewer as you submit revised patches.
Once a patch is approved, you should ask someone with commit access to land your patch.
Alternatively you can request that your patch be committed by our commit bot.
In either case, your responsibility for the patch does not end with the patch landing in the tree.
There may be regressions from your change or additional feedback from reviewers after the
patch has landed. You can watch the tree at build.webkit.org to make sure your patch builds and
passes tests on all platforms. It is your responsibility to be available should regressions arise and
to respond to additional feedback that happens after a check-in.
Changes should succeed on all platforms, but it can be difficult to test on every platform WebKit
supports. Be certain that your change does not introduce new test failures on the high-traffic Mac
or Windows ports by comparing the list of failing tests before and after your change. Your
change must at least compile on all platforms.
WebKit provides an automated system (commit-queue) for landing patches for any who would
like to use it. To use the commit-queue, set the commit-queue:? flag on your patch. A
committer will set commit-queue:+ and an automated process will download, build, run the
layout tests, and submit your patch on your behalf. If the WebKit buildbots are passing, your
patch should be landed within 15 minutes after commit-queue:+ is set. See the commit-queue
documentation for more information.
Our Committer and Reviewer policy provides details on obtaining commit and review privileges.
1. Use spaces, not tabs. Tabs should only appear in files that require them for semantic meaning,
like Makefiles.
2. The indent size is 4 spaces.
Right:
int main()
{
return 0;
}
Wrong:
int main()
{
return 0;
}
3. The contents of an outermost namespace block (and any nested namespaces with the same
scope) should not be indented. The contents of other nested namespaces should be indented.
Right:
// Document.h
namespace WebCore {
class Document {
Document();
...
};
namespace NestedNamespace {
...
}
} // namespace WebCore
// Document.cpp
namespace WebCore {
Document::Document()
{
...
}
} // namespace WebCore
Wrong:
// Document.h
namespace WebCore {
class Document {
Document();
...
};
namespace NestedNamespace {
...
}
} // namespace WebCore
// Document.cpp
namespace WebCore {
Document::Document()
{
...
}
} // namespace WebCore
4. A case label should line up with its switch statement. The case statement is indented.
Right:
switch (condition) {
case fooCondition:
case barCondition:
i++;
break;
default:
i--;
}
Wrong:
switch (condition) {
case fooCondition:
case barCondition:
i++;
break;
default:
i--;
}
5. Boolean expressions at the same nesting level that span multiple lines should have their
operators on the left side of the line instead of the right side.
Right:
if (attr->name() == srcAttr
|| attr->name() == lowsrcAttr
|| (attr->name() == usemapAttr && attr->value().domString()[0] !=
'#'))
return;
Wrong:
if (attr->name() == srcAttr ||
attr->name() == lowsrcAttr ||
(attr->name() == usemapAttr && attr->value().domString()[0] !=
'#'))
return;
Spacing
Right:
i++;
Wrong:
i ++;
Right:
y = m * x + b;
f(a, b);
c = a | b;
return condition ? 1 : 0;
Wrong:
y=m*x+b;
f(a,b);
c = a|b;
return condition ? 1:0;
f(a, b);
Wrong:
for (int i = 0 ; i < 10 ; i++)
doSomething();
f(a , b) ;
Right:
if (condition)
doIt();
Wrong:
if(condition)
doIt();
5. Do not place spaces between a function and its parentheses, or between a parenthesis and its
content.
Right:
f(a, b);
Wrong:
f (a, b);
f( a, b );
Line breaking
Right:
x++;
y++;
if (condition)
doIt();
Wrong:
x++; y++;
if (condition) doIt();
2. An else statement should go on the same line as a preceding close brace if one is present, else
it should line up with the if statement.
Right:
if (condition) {
...
} else {
...
}
if (condition)
doSomething();
else
doSomethingElse();
if (condition)
doSomething();
else {
...
}
Wrong:
if (condition) {
...
}
else {
...
}
3. An else if statement should be written as an if statement when the prior if concludes with
a return statement.
Right:
if (condition) {
...
return someValue;
}
if (condition) {
...
}
Wrong:
if (condition) {
...
return someValue;
} else if (condition) {
...
}
Braces
Wrong:
int main() {
...
}
2. Other braces: place the open brace on the line preceding the code block; place the close brace
on its own line.
Right:
class MyClass {
...
};
namespace WebCore {
...
}
Wrong:
class MyClass
{
...
};
3. One-line control clauses should not use braces unless comments are included or a single
statement spans multiple lines.
Right:
if (condition)
doIt();
if (condition) {
// Some comment
doIt();
}
if (condition) {
myFunction(reallyLongParam1, reallyLongParam2, ...
reallyLongParam5);
}
Wrong:
if (condition) {
doIt();
}
if (condition)
// Some comment
doIt();
if (condition)
myFunction(reallyLongParam1, reallyLongParam2, ...
reallyLongParam5);
Right:
for ( ; current; current = current->next) { }
Wrong:
for ( ; current; current = current->next);
1. In C++, the null pointer value should be written as 0. In C, it should be written as NULL. In
Objective-C and Objective-C++, follow the guideline for C or C++, respectively, but use nil to
represent a null Objective-C object.
2. C++ and C bool values should be written as true and false. Objective-C BOOL values should
be written as YES and NO.
3. Tests for true/false, null/non-null, and zero/non-zero should all be done without equality
comparisons.
Right:
if (condition)
doIt();
if (!ptr)
return;
if (!count)
return;
Wrong:
if (condition == true)
doIt();
if (ptr == NULL)
return;
if (count == 0)
return;
4. In Objective-C, instance variables are initialized to zero automatically. Don't add explicit
initializations to nil or NO in an init method.
Floating point literals
1. Unless required in order to force floating point math, do not append .0, .f and .0f to floating
point literals.
Right:
const double duration = 60;
setDiameter(10);
Wrong:
const double duration = 60.0;
setDiameter(10.f);
Names
1. Use CamelCase. Capitalize the first letter, including all letters in an acronym, in a class, struct,
protocol, or namespace name. Lower-case the first letter, including all letters in an acronym, in a
variable or function name.
Right:
struct Data;
size_t bufferSize;
class HTMLDocument;
String mimeType();
Wrong:
struct data;
size_t buffer_size;
class HtmlDocument;
String MIMEType();
2. Use full words, except in the rare case where an abbreviation would be more canonical and
easier to understand.
Right:
size_t characterSize;
size_t length;
short tabIndex; // more canonical
Wrong:
size_t charSize;
size_t len;
short tabulationIndex; // bizarre
3. Data members in C++ classes should be private. Static data members should be prefixed by "s_".
Other data members should be prefixed by "m_".
Right:
class String {
public:
...
private:
short m_length;
};
Wrong:
class String {
public:
...
short length;
};
Right:
@class String
...
short _length;
@end
Wrong:
@class String
...
short length;
@end
Right:
bool isValid;
bool didSendData;
Wrong:
bool valid;
bool sentData;
6. Precede setters with the word "set". Use bare words for getters. Setter and getter names should
match the names of the variables being set/gotten.
Right:
void setCount(size_t); // sets m_count
size_t count(); // returns m_count
Wrong:
void setCount(size_t); // sets m_theCount
size_t getCount();
Right:
bool convertToASCII(short*, size_t);
Wrong:
bool toASCII(short*, size_t);
8. Leave meaningless variable names out of function declarations. A good rule of thumb is if the
parameter type name contains the parameter name (without trailing numbers or pluralization),
then the parameter name isn't needed. Usually, there should be a parameter name for bools,
strings, and numerical types.
Right:
void setCount(size_t);
void doSomething(ScriptExecutionContext*);
Wrong:
void setCount(size_t count);
9. Objective-C method names should follow the Cocoa naming guidelines — they should read like a
phrase and each piece of the selector should start with a lowercase letter and use intercaps.
10. Enum members should user InterCaps with an initial capital letter.
11. Prefer const to #define. Prefer inline functions to macros.
12. #defined constants should use all uppercase names with words separated by underscores.
13. Macros that expand to function calls or other non-constant computation: these should be
named like functions, and should have parentheses at the end, even if they take no arguments
(with the exception of some special macros like ASSERT). Note that usually it is preferable to use
an inline function in such cases instead of a macro.
Right:
#define WBStopButtonTitle() \
NSLocalizedString(@"Stop", @"Stop button title")
Wrong:
#define WB_STOP_BUTTON_TITLE \
NSLocalizedString(@"Stop", @"Stop button title")
#define WBStopButtontitle \
NSLocalizedString(@"Stop", @"Stop button title")
14. #define, #ifdef "header guards" should be named exactly the same as the file (including case),
replacing the '.' with a '_'.
Right:
// HTMLDocument.h
#ifndef HTMLDocument_h
#define HTMLDocument_h
Wrong:
// HTMLDocument.h
#ifndef _HTML_DOCUMENT_H_
#define _HTML_DOCUMENT_H_
Other Punctuation
1. Constructors for C++ classes should initialize all of their members using C++ initializer syntax.
Each member (and superclass) should be indented on a separate line, with the colon or comma
preceding the member on that line.
Right:
MyClass::MyClass(Document* doc)
: MySuperClass()
, m_myMember(0)
, m_doc(doc)
{
}
MyOtherClass::MyOtherClass()
: MySuperClass()
{
}
Wrong:
MyClass::MyClass(Document* doc) : MySuperClass()
{
m_myMember = 0;
m_doc = doc;
}
MyOtherClass::MyOtherClass() : MySuperClass() {}
2. Pointer types in non-C++ code — Pointer types should be written with a space between the type
and the * (so the * is adjacent to the following identifier if any).
3. Pointer and reference types in C++ code — Both pointer types and reference types should be
written with no space between the type name and the * or &.
Right:
Image* SVGStyledElement::doSomething(PaintInfo& paintInfo)
{
SVGStyledElement* element = static_cast<SVGStyledElement*>(node());
const KCDashArray& dashes = dashArray();
Wrong:
Image *SVGStyledElement::doSomething(PaintInfo &paintInfo)
{
SVGStyledElement *element = static_cast<SVGStyledElement
*>(node());
const KCDashArray &dashes = dashArray();
#include Statements
1. All implementation files must #include "config.h" first. Header files should never include
"config.h".
Right:
// RenderLayer.h
#include "Node.h"
#include "RenderObject.h"
#include "RenderView.h"
Wrong:
// RenderLayer.h
#include "config.h"
#include "RenderObject.h"
#include "RenderView.h"
#include "Node.h"
2. All implementation files must #include the primary header second, just after "config.h". So for
example, Node.cpp should include Node.h first, before other files. This guarantees that each
header's completeness is tested. This also assures that each header can be compiled without
requiring any other header files be included first.
3. Other #include statements should be in sorted order (case sensitive, as done by the command-
line sort tool or the Xcode sort selection command). Don't bother to organize them in a logical
order.
Right:
// HTMLDivElement.cpp
#include "config.h"
#include "HTMLDivElement.h"
#include "Attribute.h"
#include "HTMLElement.h"
#include "QualifiedName.h"
Wrong:
// HTMLDivElement.cpp
#include "HTMLElement.h"
#include "HTMLDivElement.h"
#include "QualifiedName.h"
#include "Attribute.h"
Right:
// ConnectionQt.cpp
#include "ArgumentEncoder.h"
#include "ProcessLauncher.h"
#include "WebPageProxyMessageKinds.h"
#include "WorkItem.h"
#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
Wrong:
// ConnectionQt.cpp
#include "ArgumentEncoder.h"
#include "ProcessLauncher.h"
#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include "WebPageProxyMessageKinds.h"
#include "WorkItem.h"
"using" Statements
1. In header files, do not use "using" statements in namespace (or global) scope.
Right:
// wtf/Vector.h
namespace WTF {
class VectorBuffer {
using std::min;
...
};
} // namespace WTF
Wrong:
// wtf/Vector.h
namespace WTF {
using std::min;
class VectorBuffer {
...
};
} // namespace WTF
2. In header files in the WTF sub-library, however, it is acceptable to use "using" declarations at
the end of the file to import one or more names in the WTF namespace into the global scope.
Right:
// wtf/Vector.h
namespace WTF {
} // namespace WTF
using WTF::Vector;
Wrong:
// wtf/Vector.h
namespace WTF {
} // namespace WTF
Wrong:
// runtime/UString.h
namespace WTF {
} // namespace WTF
using WTF::PlacementNewAdopt;
3. In C++ implementation files, do not use statements of the form "using std::foo" to import names
in the standard template library. Use "using namespace std" instead.
Right:
// HTMLBaseElement.cpp
namespace WebCore {
} // namespace WebCore
Wrong:
// HTMLBaseElement.cpp
using std::swap;
namespace WebCore {
} // namespace WebCore
4. In implementation files, if a "using namespace" statement is for a nested namespace whose
parent namespace is defined in the file, put the statement inside that namespace definition.
Right:
// HTMLBaseElement.cpp
namespace WebCore {
} // namespace WebCore
Wrong:
// HTMLBaseElement.cpp
namespace WebCore {
} // namespace WebCore
5. In implementation files, put all other "using" statements at the beginning of the file, before any
namespace definitions and after any "include" statements.
Right:
// HTMLSelectElement.cpp
namespace WebCore {
} // namespace WebCore
Wrong:
// HTMLSelectElement.cpp
namespace WebCore {
} // namespace WebCore
Classes
Right:
class LargeInt {
public:
LargeInt(int);
...
class Vector {
public:
explicit Vector(int size); // Not a type conversion.
PassOwnPtr<Vector> create(Array); // Costly conversion.
...
Wrong:
class Task {
public:
Task(ScriptExecutionContext*); // Not a type conversion.
explicit Task(); // No arguments.
explicit Task(ScriptExecutionContext*, Other); // More than one
argument.
...
Comments
1. Use only one space before end of line comments and in between sentences in comments.
Right:
f(a, b); // This explains why the function call was done. This is
another sentence.
Wrong:
int i; // This is a comment with several spaces before it, which is
a non-conforming style.
double f; // This is another comment. There are two spaces before this
sentence which is a non-conforming style.
2. Make comments look like sentences by starting with a capital letter and ending with a period
(punctation). One exception may be end of line comments like this "if (x == y) // false for NaN".
3. Use FIXME: (without attribution) to denote items that need to be addressed in the future.
Right:
drawJpg(); // FIXME: Make this code handle jpg in addition to the png
support.
Wrong:
drawJpg(); // FIXME(joe): Make this code handle jpg in addition to the
png support.
drawJpg(); // TODO: Make this code handle jpg in addition to the png
support.
WebKit Bugzilla
A Bug's Life Cycle
Home
| New
| Search
|
Find
| Reports
| Requests
| New Account
| Log In
The status and resolution fields define and track the life cycle of a bug.
STATUS RESOLUTION
The status field indicates the general health of a The resolution field indicates what happened to
bug. Only certain status transitions are allowed. this bug.
NEW
ASSIGNED
REOPENED
RESOLVED FIXED
A resolution has been taken, and it is A fix for this bug is checked into the tree
awaiting verification by QA. From here and tested.
bugs are either re-opened and become
INVALID
REOPENED, are marked VERIFIED, or are
closed for good and marked CLOSED. The problem described is not a bug.
VERIFIED WONTFIX
QA has looked at the bug and the The problem described is a bug which will
resolution and agrees that the appropriate never be fixed.
resolution has been taken. Bugs remain in
this state until the product they were DUPLICATE
reported against actually ships, at which
The problem is a duplicate of an existing
point they become CLOSED.
bug. Marking a bug duplicate requires the
CLOSED bug# of the duplicating bug and will at
least put that bug number in the
The bug is considered dead, the resolution description field.
is correct. Any zombie bugs who choose to
walk the earth again must do so by WORKSFORME
becoming REOPENED.
All attempts at reproducing this bug were
futile, and reading the code produces no
clues as to why the described behavior
would occur. If more information appears
later, the bug can be reopened.
MOVED
Priority
This field describes the importance and order in which a bug should be fixed. This field is utilized by the
programmers/engineers to prioritize their work to be done. The available priorities range from P1 (most
important) to P5 (least important).
Severity
This field describes the impact of a bug.
Minor minor loss of function, or other problem where easy workaround is present
Platform
This is the hardware platform against which the bug was reported. Legal platforms include:
Note: When searching, selecting the option "All" does not select bugs assigned against any platform. It
merely selects bugs that are marked as occurring on all platforms, i.e. are designated "All".
Operating System
This is the operating system against which the bug was reported. Legal operating systems include:
Assigned To
This is the person in charge of resolving the bug. Every time this field changes, the status
changes to NEW to make it easy to see which new bugs have appeared on a person's list.
The default status for queries is set to NEW, ASSIGNED and REOPENED. When searching for
bugs that have been resolved or verified, remember to set the status field appropriately.
Actions:
o Home
o | New
o | Search
o |
Find
o | Reports
o | Requests
o | New Account
o | Log In
Install the Xcode Tools package from http://connect.apple.com. Xcode 2.3 or later is
required to build.
Subversion (svn) is the source code management tool used by the WebKit Open Source
Project. A Subversion client for Mac OS X 10.4 and later is available. Leopard (10.5) and
later already include a subversion client.
Python is a scripting language used by the WebKit Open Source Project. WebKit scripts
require Python 2.5 or later to run. Tiger includes Python 2.3 which is too old to support
WebKit's Python scripts.
4. Install Java for Mac OS X Developer Package
Download and install the latest OS-appropriate "Java for Mac OS X Developer Package"
from http://connect.apple.com/ (located under Downloads > Java).
Windows
1. If you own Visual Studio 2005 (newer versions of Visual Studio are currently
unsupported):
If you are building from Vista, install Service Pack 1 Update for Windows Vista.
1. KB918559
2. KB935225
3. KB943969
4. KB947315
2. If not, you can use Visual C++ Express 2005 (newer versions of Visual C++ Express
Edition are currently unsupported):
If you are building from Vista, install Service Pack 1 Update for Windows Vista.
Install the Windows Server 2003 R2 Platform SDK, then follow steps 2 and 3 of “How
to: Use Visual C++ Express Edition with the Microsoft Platform SDK.”
In addition to the paths specified in step 3 of the Platform SDK installation instructions,
you must also add the following include path. Update the Visual C++ directories in the
Projects and Solutions section in the Options dialog box:
Cygwin is a collection of utilities for Windows that includes not only a Subversion client,
but also additional tools that are required to build the WebKit source. We have made a
downloader available that automatically collects all of the required packages.
Download cygwin-downloader.zip.
Right-click cygwin-downloader.zip and choose Extract All.... Keep all the default
options and click Next until the file is extracted and the cygwin-downloader folder opens.
When all the packages have finished downloading, the Cygwin installer will launch.
Choose Install from Local Directory, then click Next until the install is complete. If you
are running Vista, the installer won't be able to launch automatically, so you will have to
manually launch Cygwin's Setup.exe.
Vista may warn you that Cygwin did not install correctly. Ignore this warning and tell
Vista that the install was successful.
If you are running Vista, click on the Start menu, enter the following command, and press
Enter:
C:\cygwin\bin\ash -c /bin/rebaseall
unset TMP
unset TEMP
Those lines would prevent picking up the Windows TMP and TEMP environment variables.
Download the February 2010 DirectX SDK (newer versions do not support Visual Studio
2005). This is needed for accelerated compositing.
6. Optional: Install the 32-bit version of Debugging Tools for Windows
Debugging Tools for Windows includes many useful debugging tools such as WinDbg
and NTSD. Some of WebKit’s tests and scripts use these tools. Follow the instructions
for installing the 32-bit version of Debugging Tools for Windows.
7. Optional: Hotfix for 64-bit Windows to disable the user-mode callback filter for
exceptions
Without the 976038 hotfix, exceptions may be thrown in callback routines that do not
cause a crash but leave the application in an inconsistent state that might cause a crash
later. You will need to click on "View and request hotfix downloads" and fill out the
form. A link to download the hotfix and a password will be emailed to you.
GTK
Follow the instructions on the BuildingGTK wiki page.
QT
Follow the instructions on the QtWebKit wiki page.
Once you have installed your developer tools, the next step is getting the code.
Getting WebKit
To download a pre-built bundle containing the latest WebKit, visit WebKit Nightly Builds.
Checking Out
To work with the WebKit source tree, you will need a Subversion client installed. See Installing
Developer Tools for information on how to install Subversion.
Mac OS X
Subversion (svn) is the source code management tool used by the WebKit Open Source
Project. A Subversion 1.4 client for Mac OS X 10.4 is available.
2. Open Terminal
Terminal resides in /Applications/Utilities. The Finder Go menu provides a quick way to
navigate there.
Windows
Alternatively you can download a snapshot of the WebKit source tree from
http://nightly.webkit.org/files/WebKit-SVN-source.tar.bz2. It is updated every six hours.
Windows
Download the WebKit Support Libraries to the root of your source tree
(C:\cygwin\home\<username>\WebKit).
If you downloaded the tarball, this will bring it up to date. Windows users must always
execute this command after first obtaining the code, since it will download additional
libraries that are needed to build.
Once you have a current tree, the next step is building WebKit.
Keeping up to Date
At any time, you can rerun the update-webkit script to update your source tree.
Building WebKit
Building WebKit requires that you have the proper developer tools installed and that you have a copy of
the WebKit source tree.
Windows
1. Open a Cygwin Shell (if not already open from checking out sources)
Double-click the Cygwin icon on your Desktop to launch a new shell.
Use the --debug option for a debug build, which includes debugging symbols and
assertions:
build-webkit --debug
Windows
A common source of build errors on Windows is Visual C++ Express forgetting the Platform
SDK paths. If you have trouble building WebKit, double check that the paths you set during step
2 of the Platform SDK Installation are still there and add them again if necessary.
Don't forget that if you have any questions or problems building WebKit, feel free to get in
touch!
Once your build has finished, you can run it inside Safari.
1. To set a default build configuration for build-webkit and other scripts, use the set-
webkit-configuration script:
set-webkit-configuration --debug
set-webkit-configuration --release
Regression Testing
The WebKit Tests
Before patches can land in any of the frameworks in the repository, the layout regression tests
must pass. To run these tests, execute the run-webkit-tests script.
The script will dump the render trees for all of the pages and diff the results against the expected
correct results. If no differences are found, then the patch has passed the tests. If any tests fail,
then the patch cannot be committed until the discrepancies in the tests are resolved.
Regression tests must be run on Leopard, since the expected results checked in were generated
on Leopard.
If you are making changes to JavaScriptCore, there is an additional test suite you must run before
landing changes. This is the Mozilla JavaScript test suite.
The JavaScript tests cover the functionality of the core JavaScript engine. This includes the
following JavaScript objects:
In addition, the JavaScript tests cover parsing, lexical conventions, expressions, statements, type
conversion, and exception handling.
Execute the run-javascriptcore-tests script. The script will run all the tests and summarize
how the results differ from what is currently expected.
After all the test runs have finished the results of tests are saved to actual.html. The script the
compares these results from your local tree against what is expected to pass/fail from the tip of
tree. If there are any regressions caused by your changes you'll be made aware of them. If you
fixed a bug that caused an existing failure, you'll also be made aware of what specific test your
fix affected.
What to do next
So you fixed a bug that fixed a test. This means you've now set a new baseline for the tree as a
result.
cp actual.html expected.html
When you land your changes, the baseline (expected.html) will be updated in the tree.
What happens if I caused a regression?
It's not the end of the world. Go back and fix your bug and rerun run-javascriptcore-tests
as many times as necessary.
Leak Hunting
Finding Leaks
Memory leaks are one of our main areas of interest. Since the average user will only notice them
by growing memory usage, we don't see as many bug reports on them as we'd like. This is some
information about how to hunt down those leaks. The Mac OS X Developer Tools include a very
useful program for leak detection. Here's how you can use it:
1. Get a fresh WebKit build, ideally a Debug build as this turns off the various custom allocators in
WebKit.
2. Set the MallocStackLogging environment variable to YES (in bash, export
MallocStackLogging=YES, in tcsh, setenv MallocStackLogging YES).
3. Run Safari using run-safari.
4. Browse around a little.
5. From the command line, run leaks Safari.
At this point, if you've found memory leaks, the leaks program will tell you how many, and give
stack traces for each. You can file a report, along with a description of what steps you took to get
the leak, at Bugzilla. Put “LEAK:” at the start of the title so that it's easy to find.
If you want to write an even better bug report, see if you can reproduce the leak by following
some specific set of steps, and include them in the bug. You can also look at the backtraces in the
leak report and see if you can eliminate duplicates. It’s useful to file a separate bug report for
each unique leak, and to consolidate duplicate leaks on different sites. Also, check out our
general document about filing bugs.
We have two ways to automatically record stack traces for leaks encountered in our standard
webkit tests. This is extremely useful since the webkit tests cover many unusual cases that one
might not run into during a short browsing session. As we continue to add webkit tests this will
continue to test for leaks in more and more corners of the code.
1. (Fast) To get a single leaks report covering all webkit tests, use run-webkit-tests --leaks. You can
also pass a specific directory or a specific test to get a leaks report covering just part of the test
hierarchy. For example run-webkit-tests --leaks dom/html/level1.
2. (Slow) To get a separate leaks report for each test, use run-webkit-tests --leaks --singly. Again,
you can pass a specific directory to run this on only part of the test hierarchy. This option is
much slower, but can be very helpful in pinning down a leak.
Fixing Leaks
Fixing memory leaks is a bit of a black art. The leak checker will tell you where the leaked
memory was allocated, but not why it was never freed. Sometimes it will be obvious from code
inspection that there is no free call to match a particular allocation. Other times, things get
trickier - especially when refcounting is involved. In that case, you know that some code has
taken a ref without releasing it, but it can be very hard to tell what code.
Here’s a trick often found useful for these situations. Fire up the application in gdb. Set
breakpoints on the appropriate ref and deref methods. Then, use the gdb “commands” feature to
set commands of “bt 10; cont” for these breakpoints. You’ll get a 10-frame backtrace for every
ref and deref, and that’s often enough to find the one that doesn’t pair up.
If you want to help with finding and fixing leaks, and you need more advice, contact us. Happy
hunting.
A layout test is simply a web page. The layout test machinery renders the web page, and then
dumps the internal representation, the render tree, with details of the layout. This lets engineers
working on the project know if they do anything that changes the layout. Once we get a test
rendering properly, we check it in as part of the layout test suite.
The following are some guidelines to follow when writing new layout tests:
1. The test should be the smallest possible code fragment that tests the feature.
2. The test should fit on one page (unless of course it’s testing scrolling).
3. The test should clearly describe what feature it is testing.
4. The test should clearly describe the expected result. It should be possible through visual
inspection alone to determine that the test has failed.
A layout test should work both in the browser itself, and in the layout test tool. The layout test
tool provides an additional object on the window object called the layout test controller with
some methods that control test output. One you should know about is the
layoutTestController.dumpAsText method. Calling this from JavaScript within a test
arranges for the output to be written out as plain text rather than as a render tree dump. This is
useful for tests that are testing something other than layout. The event creation test mentioned
above is a good example of how to do this and when it makes sense.
Some tests require pixel-level comparisons. For these tests, you must generate expected output
for a specific machine type, operating system, and color profile. When you add such a test, you
can generate new expected output automatically using the run-webkit-tests --pixel
command. This will automatically configure the color profile, and place the resulting rendered
image (and checksum) in the appropriate platform directory for checkin.
The Ahem font is useful in testing text layout, since its glyphs’ metrics are well known, and it is
always available to tests running in the layout test tool. However, if you want to view tests that
use Ahem in Safari, you should download Ahem, open it in the Font Book application, and click
on the Install Font button to install it.
The CSS working group has an excellent document on test writing guidelines for CSS tests. This
wiki article has more information on writing good tests and the DumpRenderTree tool.
Crash logs are incredibly useful when trying to track down a bug, especially if it's not
immediately reproducible.
Mac OS X
Obtaining a crash log on Mac OS X is incredibly easy since it automatically creates easily
accessible crash logs for you.
1. If WebKit has just crashed or you can easily reproduce the crash, press the Report button
on the CrashReporter dialog box to view the crash information.
2. Copy and paste the entire contents of the top portion of the CrashReporter window into
your favorite text editor and upload it as an attachment in Bugzilla.
3. If the crash report dialog does not appear or the crash is hard to reproduce, crash logs can
be retrieved from the ~/Library/Logs/CrashReporter folder.
On Leopard (Mac OS X 10.5), crash logs are stored as individually dated and time
stamped files. Despite having a “.crash” extension, they are plain text files and can be
attached directly to a bug report.
On Tiger (Mac OS X 10.4), all crashes are logged to Safari.crash.log. This is a plain
text file and can be viewed in the default Console.app or your favorite text editor. All of
Safari's crashes are logged to this file so please only attach the last crash in it. Crashes are
separated by a series of asterisks (∗∗∗∗∗∗∗∗∗∗) for easy identification.
Windows XP
Windows XP does not automatically log crashes like OS X, but it does include Dr. Watson, an
easy to set up tool that can be configured to log them.
1. In the Start menu's Run box or from a DOS or Cygwin prompt, enter the command
drwtsn32 -i.
2. A dialog box will appear informing you that Dr. Watson has been installed as the default
debugger. Press OK.
3. Crash information will now be logged to the user.dmp file in C:\Documents and
Settings\All Users\Application Data\Microsoft\Dr Watson\.
Dr. Watson will create a user.dmp file that records what WebKit was doing when it
crashed. Be careful as it is overwritten with every crash.
When reporting a WebKit bug, please upload the user.dmp file if possible.
4. Running drwtsn32 without any options or switches will bring up a window that allows
you to change various setting such as moving the log folder to a more easily accessible
location or throwing a visual alert letting you know it caught the crash.
Windows Vista
Windows Vista does not include Dr. Watson. Instead, Windows Error Reporting (WER) has
been integrated into the operating system. By default, Vista uploads the crash logs to Microsoft,
but does not save a local copy. This is configurable via the registry.
6. Double-click the file from Windows Explorer and respond affirmatively to any prompts.
7. Reboot
The next time Safari (or any other application) crashes, the crash information will be written into
a folder located inside %LOCALAPPDATA%\Microsoft\Windows\WER\ReportQueue. Check the
modification date to make sure you are using the correct file.
WERxxxx.tmp.mdmp
This is the most important file. It contains the crash dump that can be opened inside Visual
Studio or other Windows debuggers.
WERxxxx.tmp.version.txt
WERxxxx.tmp.appcompat.txt
Lists all of the DLLs loaded at the time of the crash with their version information.
WebKit Projects
There are many exciting projects that we are actively working on in the WebKit source tree. To
find out more about each project you can visit that project's home page. If you are interested in
starting a new project in the WebKit tree, contact us!
General Projects
Web Site Compatibility
The most important project that we are working on (and the one that receives the most
attention) is web site compatibility. Our top priority is ensuring that WebKit works with as many
web sites as possible. This is a cross-functional project that touches many areas of the code.
Performance
Our second highest priority after compatibility is performance. Find out about our performance
measurement tools and policies here.
Code Cleanup
We have a number of tasks in mind for code cleanup. In addition to reformatting existing code
to match our coding style guidelines, we also have plenty of work to do moving WebKit code
into WebCore now that both frameworks are open source.
Portability
Making the WebKit code more portable to other platforms is also a priority. We would like to
begin integration of ports to other platforms, such as the GTK+ port of WebCore. Find out about
our plans here.
Documentation
Want to add documents to the WebKit web site? We're interested in architecture documents,
support charts and any other documents you think will help people trying to use WebKit.
Specific Projects
CSS (Cascading Style Sheets)
Cascading Style Sheets (CSS) is a simple mechanism for adding style to Web documents. It is a
W3C standard.
The Document Object Model is a platform and language neutral interface that allows code to
dynamically access and update the content, structure and style of documents. It is a W3C
standard.
The HTML project is concerned with the implementation of the HTML and XHTML specifications
from the W3C. In addition to the W3C work on HTML and XHTML, we are also interested in the
extensions to HTML proposed by the WhatWG in the Web Apps specification.
HTML Editing
The HTML editing project provides rich text editing capabilities both as WebKit API for
applications and through support of contentEditable and designMode for use in Web
pages.
HTML Forms
The HTML form controls project is about the code to support the form controls that are
available in HTML and XHTML. We would like to extend forms to support the work of the
WhatWG (in particular the Web Forms specification). We also plan to change how the forms are
implemented in order to improve performance and portability of the controls.
JavaScript
JavaScript is the primary scripting language of the Web, and WebKit's JS engine is one of the
fastest out there. Find out about some of the interesting improvements planned for the
JavaScript interpreter.
For work on the layout and rendering of XML/HTML+CSS. This includes block and line layout,
table layout and extensions like the XUL box layout. This also includes work on rendering and
display issues.
MathML
Plug-ins
WebKit supports two types of plug-ins, cross-browser plug-ins using an enhanced form of the
Netscape plug-in API and WebKit plug-ins that are designed for use by embedded applications
that need to display native OS X content integrated with the Web document.
Printing
Find out about WebKit's printing architecture here and about planned improvements to make
page breaks work more cleanly when splitting up objects like HTML tables.
SVG is a standard from the W3C for describing two-dimensional graphics for Web documents.
This is not yet implemented in WebKit, but we are very interested in merging KSVG and the
KDOM work into our code base to achieve a fully integrated SVG solution. If you want to see
Dashboard widgets that use SVG, come on in and help make it happen!
WebKit API
The WebKit embedding API provides clients with a public API for loading, displaying and
manipulating Web content. WebKit clients can find out about plans for the API and get involved
in the design process.
WebKit has accessibility features designed to work with the VoiceOver technology of OS X. Get
involved and make suggestions for how this support can be improved in future releases. We are
also interested in how to generalize our current accessibility support to make it portable to
other platforms.
XML is the foundation of WebKit's document object model and in the future will be the
preferred format for compound documents that use HTML, SVG and MathML together. This
project covers the implementation of XML in WebKit and also other XML-related technologies
like XPath.
XSLT
XSL Transformations provide the ability to take source XML and transform it into text, HTML or
XML. This capability is a recent inclusion in WebKit, and there is still lots of interesting work to
do in this area.
The most important task that we are working on in WebKit is improving web site compatibility.
Web site compatibility is actually a generic term that covers bugs that may occur in many
different functional areas of the code, from CSS to rendering to plug-ins. Any time you
encounter a web site that works in another browser but fails in a WebKit browser you have hit a
web site compatibility bug.
These bugs can range from minor rendering defects to showstoppers that make an entire site
inaccessible. The causes of these bugs are also wide-ranging, from bugs in the way the web page
is coded to bugs in the engine itself. For this reason reduction of web site compatibility bugs is a
top priority. Only if the bug is reduced to a minimal failing test case is it easy for a developer to
determine the root cause of the problem.
1. The bug is in the Web site itself. You can test this assumption by checking the site in other
browsers like Firefox and Internet Explorer for Windows. If both of these browsers also fail on
the site, it's a safe bet that the site is to blame.
2. The HTML on the site is buggy, but WebKit's error recovery does not match other browsers. This
is a very common scenario for WebKit as our error handling is still a bit more strict than other
browsers. In this case the bug is still our responsibility, since whenever possible we want to
match other browsers' error recovery behavior.
3. WebKit has a legitimate compliance bug. This is the most important class of compatibility bug,
since we especially want valid HTML to render and behave properly.
Get Involved!
Build the latest WebKit and use it day to day. Visit all of your favorite Web sites and scrutinize
them all closely. Make sure they all work as expected, and if they don't then report problems to
us.
File Bugs
Report bugs to us for any problems you find. Get bugs into our database so that we can track
the issue and screen the bug.
Reduce Bugs
Scan the bugs in the New Bugs component and help attach reductions and minimal failing test
cases. Only when bugs are screened properly will a developer be able to determine the root
cause of the problem and move it into the appropriate component. This is one of the most
important ways you can help improve WebKit.
To help avoid regressions you can make new tests, even for features that WebKit already
handles correctly. The more regression tests we have covering a specific feature, the less likely it
is that the feature will break when we make changes.
Performance
Overview
Performance is a top priority for WebKit. We adhere to a simple directive for all work we do on
WebKit.
We have a zero-tolerance policy for performance regressions. If a patch lands that regresses
performance according to our benchmarks, then the person responsible must either back the
patch out of the tree or drop everything immediately and fix the regression.
Common excuses people give when they regress performance are, "But the new way is cleaner!"
or "The new way is more correct." We don't care. No performance regressions are allowed,
regardless of the reason. There is no justification for regressing performance. None.
1. The i-Bench test suite is the most well-known cross-browser benchmark. The HTML Load Speed
and JavaScript tests are the most important sub-tests in the suite. No check-in can regress the
benchmark scores for these tests. As of this writing, you can get the i-Bench test suite from this
page on the Lionbridge website. After accepting the license agreement you'll be able to
download the suite from an FTP site at pcmag.com.
2. Our internal page load test suite (called the PLT for short) must also not regress. The PLT
contains pages that are representative of sites that are encountered in the real world. The
harness itself is built into Safari and is accessible from the Debug menu. You can actually make
Safari run the PLT on any set of test pages. Unfortunately, the pages we use internally at Apple
contain copyrighted material and therefore cannot be open source at this time. We hope that in
the future sites will be willing to donate snapshots of their front pages so that an open source
cross-browser test suite can be developed with content that is not as homogenous as the i-
Bench pages.
Get Involved!
If you have your own performance tests, run WebKit through them daily. Make sure that the
performance of the sites you care about does not regress. Test the above benchmarks on your
hardware to help double-check that there have not been any regressions. Remember, the best
way to stay fast is to never let your code become slower.
We have discussed with Mozilla and Opera the idea of an open-source cross-browser
benchmark. The stumbling block to the construction of such a test suite is that we need to get
buy-in from high profile sites like Google, Amazon or Yahoo to use snapshots of their front pages
in the benchmark. The benefits of having your site in such a benchmark are obvious, since
browser vendors will make your sites faster as they optimize for the content of the benchmark.
If you work for one of these high profile sites we encourage you to contact us if you are
interested in having your company contribute content to such a benchmark.
OS X now has an excellent profiling tool called Shark. If you find operations that are slow in
WebKit, we encourage you to use Shark to isolate performance problems and file bugs with that
information. Here is a link to get you started using Shark.
Code Cleanup
Overview
We have a number of code cleanup tasks in mind for WebKit, WebCore and JavaScriptCore. We
have established coding style guidelines for the frameworks and expect to be cleaning up the
code so that it matches these guidelines. In addition there are several cleanup tasks for each
framework to better refactor code or to make simplifications that will help make the code easier
to understand.
Get Involved!
Follow the Coding Style Guidelines
We welcome patches that clean up code to follow our coding style guidelines. We especially
encourage contributors to clean up code that they are already working on. It is less common for
contributors to update style without making substantive changes. If you would like to clean up
code without making substantive changes, you are advised to check with project members first.
Eliminate Redundant Code in WebKit and WebCore
Now that WebKit and WebCore are both open source, there is less of a need for an artificial
barrier between the two frameworks. Much of the Objective-C code that is in WebKit can be
moved to WebCore and converted to C++. This will improve portability, performance, and
eliminate redundant constructs (like the fact that both WebCore and WebKit know about
loading subresources and have their own frame trees).
Portability
Overview
Welcome to the portability project page. In addition to making our code more portable, we are
also interested in hosting ports of WebKit to other platforms. For example, WebCore has already
been ported to GTK+ and we are interested in hosting this port in our repository. We are also
interested in ports of WebKit to other platforms like Windows. This project is concerned with
how to do the code refactoring necessary to improve portability, thus making life easier for those
doing ports, as well as with the ports themselves.
Get Involved!
Move WebKit code into WebCore
Over time the WebKit framework has grown to contain a lot of code written in Objective-C that
has no real business being in this framework. Now that both frameworks are open source, we
would like to move as much of this code as possible from WebKit into WebCore. This means
rewriting the code to be C++ instead of Objective-C to make the code more portable. Ultimately
we would like WebKit to be nothing more than the embedding APIs for a given platform and
infrastructure/glue code that is needed to tie into a specific platform. All of the remaining logic
should move to WebCore.
Not all platforms have code for handling cookies, authentication, SSL, caching, network loading,
or image decoding. We would be interested in implementations of these capabilities that could
optionally be used on platforms that do not have this support. On platforms that do, the
implementation of the cross-platform abstraction could call into the system. One possibility for
obtaining this missing functionality is to port Mozilla's image rendering and networking libraries
to Qt (eliminating the XPCOM and converting the use of strings, etc. to QString).
One port of WebCore already exists, the GTK+ port. We are interested in integrating this into
our source tree, and believe that doing so will help us to refactor our code to make future ports
easier.
Help Porting!
Want to help with porting to Windows or some other platform? Contact us and start submitting
patches!
Documentation
Overview
As you can see we've gotten a good start on documenting the projects that you can get involved with in
WebKit. However we have many more documents that we would like to write. The documentation
project tracks everything from the current Web site design to ideas for new developer docs and
technical docs.
Get Involved!
Here are some tasks that you can help with.
Developer Documentation
We would like to build up a web site that describes in detail the DOM methods, CSS properties
and APIs that are supported by the different versions of Safari and WebKit, so that people have
a place to go to where they can find out what we support.
Project Documentation
We can always use more technical documentation, from helpful tutorials on using WebKit APIs
to technical documents that describe how a particular functional area of the code works.
Use Blogs/Wikis
We may in the future use blogs or wikis for the project pages. This would enable them to be
updated more easily and to allow collaboration to take place within the project pages
themselves.
Existing Documentation
This is the project page for WebKit's Cascading Style Sheets (CSS) implementation. CSS is a
W3C specification, and WebKit has implemented virtually all of CSS1, most of CSS2.1 and
even some CSS3. At this time we are focusing our efforts on completing CSS1 and CSS2.1
support. Some features of CSS3 are far enough along (like selectors) that they can be
implemented safely as well.
Get Involved!
View bugs in the CSS component in Bugzilla.
Here are some of the tasks that you can get involved with in CSS.
Only a handful of CSS1 bugs remain, primarily with text-transform capitalize. Look for bugs that
have been prefaced with "CSS1:" in the title. Complete support is measured by passing the CSS1
test suite.
Most of CSS2.1 has been implemented in WebKit, but a few holes remain. The new white-space
values pre-wrap and pre-line are not yet supported. Some of these features have been
implemented in the current KHTML tree, and a merge may be possible for some of these
features.
Many of the CSS3 selectors are already supported by WebKit, but a few remain. Help complete
support and test against the CSS selectors test suite to verify compliance.
Check out the CSS2.1 test suite and file compliance bugs so that we can track open issues with
our CSS2.1 compliance.
The Document Object Model (DOM) is a standardized software interface that allows code
written in JavaScript and other languages to interact with the contents of an HTML document.
The Document Object Model consists of a series of classes that represent HTML elements,
events, and so on, each of which contains methods that operate on those elements or events.
Get Involved!
View bugs in the HTML DOM and XML DOM component in Bugzilla.
If you find a DOM bug in the latest nightly build of WebKit, please file a bug report.
Development discussions take place on Freenode IRC in #webkit.
HTML and XHTML (HyperText Markup Language)
Overview
This is the home page for work on WebKit's HTML and XHTML implementation. HTML work
generally falls into four categories: work on site compatibility and handling of invalid HTML,
work on finishing HTML4 support, extensions to HTML like the canvas element used in
Dashboard, and XHTML work.
Get Involved!
View bugs in the HTML component in Bugzilla.
There are a handful of HTML4 issues remaining, including adding support for a few more
attributes for legacy HTML to APPLET and OBJECT, implementing the BDO element, and
implementing alignment inheritance in table columns.
Improve XHTML
We want to improve our XHTML rendering, making it as incremental as HTML and making sure
entity support and scripts work properly.
Extend HTML
We are interested in the WhatWG work to extend HTML to have functionality that has not been
covered in any other HTML specifications.
HTML Editing
Overview
Welcome to the HTML editing home page. HTML editing is a new feature that shipped with
Safari 1.3 on Panther and Safari 2.0 on Tiger. Most importantly the WebKit editing engine is
used to compose mail messages in Mail on Tiger. HTML editing can also be used in Web pages
using WinIE-compatible APIs like contentEditable and designMode.
Architecturally the editor operates as a series of commands that are executed on a document's
object model tree. Each command can be undone and redone just by performing the appropriate
set of DOM operations. The implementation of these commands and other editing infrastructure
can be found in the WebCore framework in the editing subdirectory.
Editing operations are also part of the WebKit API, and so there is some overlap with that
project. Up until now our focus has mostly been on editing for applications that embed WebKit,
but we plan to focus in the future on improving the in-page editing support via contentEditable.
Get Involved!
View bugs in the HTML editing component in Bugzilla.
Below are some of the tasks that need work in HTML editing.
Right now there are a number of issues with editable divs in a Web page. The selection
highlighting is not confined to the div, and extending the selection across editable and non-
editable content should not be possible. In addition WebKit always clears the selection on a
mouse down, and other browsers actually only do this if you mouse down on text.
Lists and tables are two editing features that could use a richer user interface so that these sorts
of features could be made available to mail and to other WebKit applications.
We want to support more of WinIE's editing APIs, including more commands and text ranges.
We welcome any WinIE-compatible patches that improve editing support to match WinIE.
HTML Forms
Overview
Welcome to the project page for the HTML form controls. Form controls are the various widgets
that can be used in an HTML form and that can participate in form submission. The code in the
engine that talks to the controls is in the WebCore framework. The DOM elements are under the
html directory, and the rendering objects are under the rendering directory.
Get Involved!
View bugs in the HTML Forms component in Bugzilla.
Below is a sampling of interesting open issues with our HTML form controls. To get involved
contact us!
Form controls have recently switched from using standard AppKit controls to being rendered
within the engine itself. This allows us to support more CSS properties for controls, and makes
our code more portable to other platforms. Because this is such a major architectural change,
we ask that you scrutinize the new controls closely and report any bugs.
JavaScript
Overview
This is the project page for WebKit's JavaScript implementation. JavaScript is the primary
programming language used on web pages. Originally named LiveScript and now also known as
ECMAScript, it's a safe, dynamic language that's arguably one of the most well-known
programming languages in the world. There's a JavaScript standard, created by ECMA. WebKit's
JavaScript engine, JavaScriptCore, based on KJS, is a framework separate from WebCore and
WebKit, and is used on Mac OS X for applications other than web page JavaScript.
Get Involved!
View bugs in the JavaScriptCore component in Bugzilla.
Here are some of the tasks that you can get involved with in JavaScript.
The garbage collector in JavaScriptCore has been improved quite a bit from the earliest versions.
But much greater efficiency can be achieved with a garbage collector that uses a generational
algorithm, so we don't have to mark all the objects every time we garbage collect. This should
make JavaScript run significantly faster.
JavaScriptCore has an implementation of the Mozilla JavaScript Test Suite, and there are
currently many failures. Fixing any of those failures would help our JavaScript engine be more
compliant with the specification, and more compatible with real-world web sites as well.
Language Extensions
The Mozilla project has begun adding some extensions to JavaScript. Someone needs to
evaluate these and decide which of them we should implement. We should also consider
extensions of our own driven by demand in contexts like Dashboard widgets.
Layout and rendering provides the core functionality to display a markup language such as
HTML, SVG, or MathML. A render object tree is generated from the markup and those tree
object instances are responsible for the layout and subsequent rendering of the content.
MathML
Overview
Welcome to the project page for MathML. MathML is a specification from the W3C for the
inclusion of mathematical expressions in Web documents. At this time, work is underway to
implement MathML in WebKit. Like SVG, we would like MathML to be a first-class citizen in
WebKit, using our DOM, CSS and JavaScript engines.
Just as with SVG, we would like to work on making improvements to our DOM and reconciling
with the KDOM work that has been done for KSVG2 so that SVG and MathML can share some
of the same compound document infrastructure (and also to ensure that a MathML
implementation can be shared between KDE and OS X).
More information about this project is provided on the MathML Wiki page.
Get Involved!
Printing
Overview
Welcome to the printing project page. Printing in WebKit is closely tied to the layout and
rendering code. When you print in WebKit, the existing render tree is converted into a new
render tree with print styles applied. That new render tree then gets a layout. The big flaw in
WebKit's printing architecture right now is that page breaks are determined at a simulated "paint"
time rather than during layout itself. This means that at best all you can hope to do is try to find
an optimal position for a break without altering the layout of the Web document at all.
Get Involved
Rework Printing
Printing needs to be reworked so that render objects know how to split themselves across
breaks. This allows two separate formatting contexts (like two adjacent table cells) to still have
their contents both break cleanly across a page. This work is also important for future
technology like CSS3 multi-column support. The code that splits render objects across pages
could obviously be leveraged to also split render objects across column breaks as well.
Welcome to the project page for SVG. At this time there is an experimental SVG implementation
in WebKit. We imported KDE's excellent KSVG2 implementation and have tweaked it to
integrate seamlessly with the rest of WebCore. There is still much work to be done to finish off
some advanced SVG features such as animation and SVG fonts. With your help we look forward
to many great uses of SVG throughout the web and Mac OS X!
Get Involved!
Get on IRC
There is still much work to be done to complete our implementation of SVG 1.1. Development
discussions take place on Freenode IRC in #ksvg and #webkit. Come get involved as we flesh out
our SVG implementation for WebKit!
Test WebKit+SVG
SVG support is enabled in the latest nightly builds. Give it a whirl; try to break it! If WebKit
doesn't render your favorite SVG perfectly, please file a bug.
XSLT
Overview
Welcome to the project page for WebKit's XSLT implementation. XSLT is a W3C standard for
defining how to transform source XML into a result document that can be examined using the
DOM or displayed as a Web document. Here is a test file that demonstrates client-side XSLT in
action.
WebKit uses the excellent libxslt library to do XSL transformations. Bugs in WebKit's XSLT
support fall into two categories: either they are bugs in libxslt itself, or they are bugs in WebKit's
glue code that interacts with libxslt. The following page at xmlsoft.org has a list of helpful
resources and explains the process of bug reporting and getting help for bugs in libxslt. Even if
the bug is in libxslt, file a tracking bug in WebKit's XSLT component and paste in a link to the
corresponding libxslt bug. That way we can track the issue and know that an update to the
version of libxslt on the system may be necessary.
WebKit's implementation of XSLT can be found in the WebCore framework in the khtml/xsl
subdirectory. There are two classes of interest, XSLStyleSheetImpl and XSLTProcessorImpl.
The style sheet class shares a common base with CSS style sheets, and exists as an object-
oriented expression of the stylesheets that WebKit encounters when it parses the source XML
file. The processor wraps the code that actually performs the transformation. It takes the
stylesheets and source XML and produces result text that is then fed back into WebKit for
parsing as HTML, XML or plain text.
Get Involved!
Below is a sampling of interesting open issues with WebKit's XSLT support. If you wish to sign
up for any of these tasks, send mail to webkit-dev@lists.webkit.org or comment in the
appropriate bug.
The XSLTProcessor that performs the transformation using libxslt does so on the UI thread.
Therefore a transformation that takes a long time to complete will block the UI of a WebKit
application. The code should be restructured so that both synchronous and asynchronous
transformations are allowed, since until JavaScript can be suspended/resumed a synchronous
transformation mode must be possible in order for a JS API for XSL transformations to work.
Technical Articles
Version 4, 2010-08-27
History
Many objects in WebKit are reference counted. The pattern used is that classes have member
functions ref and deref that increment and decrement the reference count. Each call to ref has to
be matched by a call to deref. When the function is called on an object with a reference count of
1, the object is deleted. Many classes in WebKit implement this pattern by deriving from the
RefCounted class template.
Back in 2005, we discovered that there were many memory leaks, especially in HTML editing
code, caused by misuse of ref and deref calls.
We wanted to use smart pointers to mitigate the problem. However, some early experiments
showed that smart pointers led to additional manipulation of reference counts that hurt
performance. For example, for a function that took a smart pointer as a parameter and returned
that same smart pointer as a return value, just passing the parameter and returning the value
would increment and then decrement the reference count two to four times as the object moved
from one smart pointer to another. So we looked for an idiom that would let us use smart
pointers and avoid this reference count churn.
The inspiration for a solution came from the C++ standard class template auto_ptr. These objects
implement a model where assignment is transfer of ownership. When you assign from one
auto_ptr to another, the donor becomes 0.
Maciej Stachowiak devised a pair of class templates, RefPtr and PassRefPtr, that implement this
scheme for WebCore’s intrusive reference counting.
Raw pointers
When discussing smart pointers such as the RefPtr class template we use the term raw pointer to
refer to the C++ language’s built in pointer type. Here’s the canonical setter function, written
with raw pointers:
class Document {
...
Title* m_title;
}
Document::Document()
: m_title(0)
{
}
Document::~Document()
{
if (m_title)
m_title->deref();
}
RefPtr
RefPtr is a simple smart pointer class that calls ref on incoming values and deref on outgoing
values. RefPtr works on any object with both a ref and a deref member function. Here’s the setter
function example, written with RefPtr:
class Document {
...
RefPtr<Title> m_title;
}
RefPtr<Node> createSpecialNode()
{
RefPtr<Node> a = new Node;
a->setSpecial(true);
return a;
}
RefPtr<Node> b = createSpecialNode();
For purposes of this discussion, lets assume that the node object starts with a reference count of 0
(more on this later). When it’s assigned to a, the reference count is incremented to 1. The
reference count is incremented to 2 to create the return value, then decremented back to 1 when a
is destroyed. Then the reference count is incremented to 2 to create b, and then decremented back
to 1 when the return value of createSpecialNode is destroyed.
(If the compiler implements the return value optimization, there may be one less increment and
decrement of the reference count.)
The overhead of reference count churn is even greater when both function arguments and return
values are involved. The solution is PassRefPtr.
PassRefPtr
PassRefPtr is like RefPtr with a difference. When you copy a PassRefPtr or assign the value of a
PassRefPtr to a RefPtr or another PassRefPtr, the original pointer value is set to 0; the operation
is done without any change to the reference count. Let’s take a look at a new version of our
example:
PassRefPtr<Node> createSpecialNode()
{
PassRefPtr<Node> a = new Node;
a->setSpecial(true);
return a;
}
RefPtr<Node> b = createSpecialNode();
The node object starts with a reference count of 0. When it’s assigned to a, the reference count is
incremented to 1. Then a gets set to 0 when the return value PassRefPtr is created. Then the
return value is set to 0 when b is created.
However, as the Safari team learned when we started programming with PassRefPtr, the rule that
a pointer becomes 0 when it’s assigned to another variable can easily lead to mistakes.
Since we recommend use of RefPtr in all cases except when passing arguments to or returning
values from a function, there will be times when you have a RefPtr and wish to transfer
ownership as PassRefPtr does. RefPtr has a member function named release that does the trick.
It sets the value of the original RefPtr to 0 and constructs a PassRefPtr, without changing
reference counts.
PassRefPtr<Node> createSpecialNode()
{
RefPtr<Node> a = new Node;
a->setCreated(true);
return a.release();
}
RefPtr<Node> b = createSpecialNode();
This keeps the efficiency of PassRefPtr while reducing the chance that its relatively tricky
semantics will cause problems.
When using a RefPtr to call a function that takes a raw pointer, use the get function.
printNode(stderr, a.get());
However, many operations can be done on a RefPtr or PassRefPtr directly, without resorting to
an explicit get call.
RefPtr<Node> a = createSpecialNode();
Node* b = getOrdinaryNode();
// the * operator
*a = value;
// the -> operator
a->clear();
// the ! operator
if (!a)
log("empty");
Normally, RefPtr and PassRefPtr enforce a simple rule; they always balance ref and deref calls,
guaranteeing a programmer can’t miss a deref. But in the case where we have a raw pointer,
already have a reference count, and want to transfer ownership the adoptRef function should be
used.
To transfer from a RefPtr to a raw pointer without changing the reference count, PassRefPtr
provides the leakRef function.
Since leakRef is rarely used, it’s provided only in the PassRefPtr class, hence the need to call
release, then leakRef.
In the examples in this discussion, we talked about objects with a reference count of 0. However,
for efficiency and simplicity, the RefCounted class doesn't use a reference count of 0 at all.
Objects are created with a reference count of 1. The best programming idiom to use is to put
such objects right into a RefPtr to make it impossible to forget to deref the object when done
with it. This means that anyone calling new on such an object should immediately call adoptRef.
In WebCore we use functions named create instead of direct calls to new.
// preferred style
PassRefPtr<Node> Node::create()
{
return adoptRef(new Node);
}
RefPtr<Node> e = Node::create();
Because of the way adoptRef and PassRefPtr are implemented, this is an efficient idiom. The
object starts with a reference count of 1 and no manipulation of the reference count happens at
all.
// preferred style
PassRefPtr<Node> createSpecialNode()
{
RefPtr<Node> a = Node::create();
a->setCreated(true);
return a.release();
}
RefPtr<Node> b = createSpecialNode();
The node object is put into a PassRefPtr by a call to adoptRef inside Node::create, then passes
into a and is released and passes into b, all without touching the reference count.
The RefCounted class implements a runtime check so we get an assertion failure if we create an
object and call ref or deref without first calling adoptRef.
Guidelines
We’ve developed these guidelines for use of RefPtr and PassRefPtr in WebKit code.
Local variables
If ownership and lifetime are guaranteed, a local variable can be a raw pointer.
If the code needs to hold ownership or guarantee lifetime, a local variable should be a RefPtr.
Local variables should never be PassRefPtr.
Data members
If ownership and lifetime are guaranteed, a data member can be a raw pointer.
If the class needs to hold ownership or guarantee lifetime, the data member should be a RefPtr.
Data members should never be PassRefPtr.
Function arguments
If a function does not take ownership of an object, the argument should be a raw pointer.
If a function does take ownership of an object, the argument should be a PassRefPtr. This
includes most setter functions. Unless the use of the argument is very simple, the argument
should be transferred to a RefPtr at the start of the function; the argument can be named with a
“prp” prefix in such cases.
Function results
If a function’s result is an object, but ownership is not being transferred, the result should be a
raw pointer. This includes most getter functions.
If a function’s result is a new object or ownership is being transferred for any other reason, the
result should be a PassRefPtr. Since local variables are typically RefPtr, it’s common to call
release in the return statement to transfer the RefPtr to the PassRefPtr.
New objects
New objects should be put into a RefPtr as soon as possible after creation to allow the smart
pointers to do all reference counting automatically.
For RefCounted objects, the above should be done with the adoptRef function.
Best idiom is to use a private constructor and a public create function that returns a PassRefPtr.
We should add answers to any frequently asked questions are not covered by this document. One
or more of the following topics could also be covered by this document.
The “protector” idiom, where a local RefPtr variable is used to keep an object alive.
Perils of programming with TreeShared.
Our desire to eliminate TreeShared and instead have m_firstChild and m_next be ListRefPtr or
the equivalent.
How we we mix reference counting with garbage collection to implement the DOM and the
JavaScript and Objective-C DOM bindings.
Comparison of our intrusive reference counting with other schemes such as the external
reference counting in Boost shared_ptr.
The OwnPtr class template, and how it can be used with PassOwnPtr and adoptPtr.
The OwnArrayPtr class template, and PassOwnArrayPtr.
The RetainPtr class template, and the lack of a PassRetainPtr.
The ListRefPtr class template.
If you have any comments on the above or other ideas about improving the clarity, scope, or
presentation, please send mail to the WebKit mailing list.
Background
WebKit provides a number of macros to assert that conditions in the code are met. They are
defined in Source/JavaScriptCore/wtf/Assertions.h. This document provides an overview of the
various macros, including guidelines and best practices for their use.
Types of ASSERT macros
The ASSERT() macro and its variants are compiled out of release builds. They are meant for use
during the development process to catch programming mistakes. For those macros that accept an
expression as an argument, the expression is also compiled out of release builds and thus incurs
no overhead in shipping code.
ASSERT(expression) - for use during development to ensure that unexpected conditions do not
occur. If the expression evaluates to false then abort execution and break into the debugger.
ASSERT_UNREACHED() - for use when a certain branch of code should never be executed.
if (condition) {
...
} else {
// This should never happen.
ASSERT_UNREACHED();
}
ASSERT_UNUSED(variable, expression) - for assertions that check the value of otherwise unused
variable. The need for this becomes apparent if you consider the case where you want to assert
an expression that uses a variable that wouldn't otherwise be used in the enclosing function.
ASSERT() can't be used in this case because in a release build the compiler would warn about the
unused variable. ASSERT_UNUSED() avoids this warning.
Example from Source/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp :
void ExecutablePool::systemRelease(const ExecutablePool::Allocation&
alloc)
{
int result = munmap(alloc.pages, alloc.size);
// result not used outside the ASSERT().
ASSERT_UNUSED(result, !result);
}
CRASH() raises a fatal error resulting in program termination and triggering either the debugger
or the crash reporter. It is active in both debug & release mode. CRASH() directly affects users
in that it will disrupt or end their browsing session. If a browser vendor traces crashes, it can be
extremely helpful in diagnosing hard to find issues that may only occur on users' machines.
The expression inside the ASSERT and ASSERT_UNUSED macro is compiled out of release
builds together with the macro itself. If the expression that's used has side effects, its omission in
release build can lead to programming errors that don't manifest in debug builds.
The benefits of using CRASH:
If a browser vendor traces crashes in their software, CRASH() can provide vital information from
end users to allow an issue to be resolved.
Code after CRASH() is guaranteed unreachable, which can help prevent some bugs from being
security liabilities.
Use of the CRASH macro turns a programming error into a crash, blowing away a webpage or an
entire web browser in cases that otherwise might be harmless.
Checking for the error condition in release builds may slow the program down.
Use ASSERT() for things that should never happen, but if they do will cause incorrect results
rather than a crash or memory corruption.
Assertions are claims that a programmer knows to be true, and they fire only when that
programmer turns out to be wrong because there is some kind of programming mistake. There
should be no "wishful thinking" involved. For example, ASSERT() should not be used to verify
that a file system call has succeeded, because there is no way for a programmer to guarantee
that.
Use CRASH() for cases that shouldn't happen, but if they do would be unrecoverable. e.g. out of
memory errors.
If you have any comments on the above or other ideas about improving the clarity, scope, or
presentation, please send mail to the WebKit mailing list.
This is the first of a series of posts designed to help people interested in hacking on WebCore’s
rendering system. I’ll be posting these articles as I finish them on this blog, and they will also be
available in the documentation section of the Web site.
A Web page is parsed into a tree of nodes called the Document Object Model (DOM for short).
The base class for all nodes in the tree is Node.
Node.h
Nodes break down into several categories. The node types that are relevant to the rendering code
are:
Document – The root of the tree is always the document. There are three document classes,
Document, HTMLDocument and SVGDocument. The first is used for all XML documents other
than SVG documents. The second applies only to HTML documents and inherits from
Document.
The third applies to SVG documents and also inherits from Document.
Document.h
HTMLDocument.h
Elements – All of the tags that occur in HTML or XML source turn into elements. From a
rendering perspective, an element is a node with a tag name that can be used to cast to a
specific subclass that can be queried for data that the renderer needs.
Element.h
Text – Raw text that occurs in between elements gets turned into text nodes. Text nodes store
this raw text, and the render tree can query the node for its character data.
Text.h
At the heart of rendering is the render tree. The render tree is very similar to the DOM in that it is
a tree of objects, where each object can correspond to the document, elements or text nodes. The
render tree can also contain additional objects that have no corresponding DOM node.
RenderObject.h
The RenderObject for a DOM node can be obtained using the renderer() method on Node.
The following methods are most commonly used to walk the render tree.
Renderers are created through a process on the DOM called attachment. As a document is parsed
and DOM nodes are added, a method called attach gets called on the DOM nodes to create the
renderers.
void attach()
The attach method computes style information for the DOM node. If the display CSS property
for the element is set to none or if the node is a descendant of an element with display: none set,
then no renderer will be created. The subclass of the node and the CSS display property value are
used together to determine what kind of renderer to make for the node.
Attach is a top down recursive operation. A parent node will always have its renderer created
before any of its descendants will have their renderers created.
Renderers are destroyed when DOM nodes are removed from the document or when the
document gets torn down (e.g., because the tab/window it was in got closed). A method called
detach gets called on the DOM nodes to disconnect and destroy the renderers.
void detach()
Detachment is a bottom up recursive operation. Descendant nodes will always have their
renderers destroyed before a parent destroys its renderer.
During attachment the DOM queries CSS to obtain style information for an element. The
resultant information is stored in an object called a RenderStyle.
RenderStyle.h
Every single CSS property that WebKit supports can be queried via this object. RenderStyles are
reference counted objects. If a DOM node creates a renderer, then it connects the style
information to that renderer using the setStyle method on the renderer.
void setStyle(RenderStyle*)
The renderer adds a reference to the style that it will maintain until it either gets a new style or
gets destroyed.
The RenderStyle can be accessed from a RenderObject using the style() method.
This diagram from the CSS2.1 spec illustrates the parts of a CSS box. The following methods
can be used to obtain the border/margin/padding widths. The RenderStyle should not be used
unless the intent is to look at the original raw style information, since what is actually computed
for the RenderObject could be very different (especially for tables, which can override cell
padding and have collapsed borders between cells).
The width() and height() methods give the width and height of the box including its borders.
The client box is the area of the box excluding borders and scrollbars. Padding is included.
The term content box is used to describe the area of the CSS box that excludes the borders and
padding.
IntRect contentBox() const;
int contentWidth() const { return clientWidth() - paddingLeft() -
paddingRight(); }
int contentHeight() const { return clientHeight() - paddingTop() -
paddingBottom(); }
When a box has a horizontal or vertical scrollbar, it is placed in between the border and the
padding. A scrollbar’s size is included in the client width and client height. Scrollbars are not
part of the content box. The size of the scrollable area and the current scroll position can both be
obtained from the RenderObject. I will cover this in more detail in a separate section on
scrolling.
Boxes also have x and y positions. These positions are relative to the ancestor that is responsible
for deciding where this box should be placed. There are numerous exceptions to this rule,
however, and this is one of the most confusing areas of the render tree.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
2. bartocc Says:
August 9th, 2007 at 10:54 am
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
In the previous entry I talked about the basic structure of a CSS box. In this article I’m going to
talk about subclasses of RenderBox and about the concepts of block and inline.
A block flow is a box designed either to contain lines (e.g., a paragraph) or to contain other
blocks that it stacks vertically. Example block flow elements in HTML are p and div.
An inline flow is an object that is designed to be part of a line. Example inline flow elements in
HTML are a, b, i and span.
In WebCore, there are three renderer classes that cover block and inline flows. RenderBlock,
RenderInline and their common superclass RenderFlow.
RenderFlow.h
RenderBlock.h
RenderInline.h
An inline flow can be changed to a block flow (and vice versa) using the CSS display property.
In addition to block and inline flows, there is another kind of element that can act as a block or
inline: the replaced element. A replaced element is an element whose rendering is unspecified by
CSS. How the contents of the object render is left up to the element itself. Examples of replaced
elements are images, form controls, iframes, plugins and applets.
A replaced element can also be either block-level or inline-level. When a replaced element acts
as a block, it will get stacked vertically as though it represents its own paragraph. When a
replaced element acts as an inline, it will be part of a line inside a paragraph. Replaced elements
are inline by default.
Form controls are actually a strange special case. They are still replaced elements, but because
they are implemented by the engine, controls actually ultimately subclass from RenderBlock. As
a result, the concept of being replaced can’t really be confined to a single common subclass, and
is therefore represented as a bit on RenderObject instead. The isReplaced method can be used
to ask if an object is a replaced element.
Images, plugins, frames and applets all inherit from a common subclass that implements replaced
element behavior. This class is RenderReplaced.
RenderReplaced.h
One of the most confusingly named objects in CSS is the inline-block. Inline blocks are block
flows that are designed to sit on a line. In effect they are like inline replaced elements on the
outside, but on the inside they are block flows. The display property in CSS can be used to create
inline blocks. Inline blocks will report true if asked if they are replaced.
Tables
Tables in HTML are block-level by default. However they can also be made into inlines using
the CSS display property with a value of inline-table.
Again, from the outside an inline-table is like an inline replaced element (and will return true
from isReplaced), but on the inside the object is still just a table.
In WebCore the RenderTable class represents a table. It inherits from RenderBlock for reasons
that will be covered in the positioning section later.
RenderTable.h
Text
Raw text is represented using the RenderText class. Text is always considered inline by
WebCore, since it is always placed on lines.
RenderText.h
Getting Block and Inline Information
The most basic method for obtaining block vs. inline status is the isInline function. This
method asks if an object is designed to be part of a line. It does not care what the interior of the
element is (e.g., text, image, an inline flow, an inline-block or an inline-table).
One of the common mistakes people make when working with the render tree is assuming that
isInline means an object is always an inline flow, text or an inline replaced element. However
because of inline-blocks and inline-tables, this method can return true even for these objects.
To ask if an object is actually a block or inline flow, the following methods should be used.
These methods are essentially asking questions about the interior of the object. An inline-block
for example is still a block flow and not an inline flow. It is inline on the outside, but on the
inside it is a block flow.
The exact class type can be queried for blocks and inlines using the following methods.
The isRenderBlock method is useful in the context of positioning, since both block flows and
tables act as positioned object containers.
Block flows have a simple invariant regarding their children that the render tree always obeys.
That rule can be summarized as follows:
All in-flow children of a block flow must be blocks, or all in-flow children of a block flow must be
inlines.
In other words, once you exclude floating and positioned elements, all of the children of a block
flow in the render tree must return true from isInline or they must all return false from
isInline. The render tree will change its structure as needed to preserve this invariant.
The childrenInline method is used to ask whether the children of a block flow are inlines or
blocks.
Children of inline flows have an even simpler invariant that must be maintained.
Anonymous Blocks
In order to preserve the block flow child invariant (only inline children or only block children),
the render tree will construct objects called anonymous blocks. Consider the following example:
<div>
Some text
<div>
Some more text
</div>
</div>
In the above example, the outer div has two children: some text and another div. The first child is
an inline, but the second child is a block. Because this combination of children violates the all-
inline or all-block child rule, the render tree will construct an anonymous block flow to wrap the
text. The render tree therefore becomes:
<div>
<anonymous block>
Some text
</anonymous block>
<div>
Some more text
</div>
</div>
The isAnonymousBlock method can be used to ask if a renderer is an anonymous block flow.
Whenever a block flow has inline children and a block object suddenly tries to insert itself as a
child, anonymous blocks will be created as needed to wrap all of the inlines. Contiguous inlines
will share a single common anonymous block, so the number of anonymous blocks can be kept
to a minimum. The makeChildrenNonInline method in RenderBlock is the function that
performs this adjustment.
One of the nastiest constructs you will see in HTML is when a block is placed inside an inline
flow. Here is an example:
The two divs violate the invariant that all of the children of the bold element must be inlines. The
render tree has to perform a rather complicated series of steps in order to fix up the tree. Three
anonymous blocks are constructed. The first block holds all of the inlines that come before the
divs. The second anonymous block holds the divs. The third anonymous block holds all of the
inlines that come after the divs.
Notice that the bold and italic renderers had to split into two render objects, since they are in
both the anonymous pre block and the anonymous post block. In the case of the bold DOM
element, its children are in the pre block, but then continue into the middle block and then finally
continue into the post block. The render tree connects these objects via a continuation chain.
The first bold renderer in the pre block is the one that can be obtained from the b DOM element
using the element’s renderer() method. This renderer has as its continuation() the middle
anonymous block. The middle anonymous block has as its continuation() the second bold
renderer. In this way code that needs to examine the renderers that represent the children of the
DOM element can still do so relatively easily.
In the above example the i DOM element also split. Its children are all in the pre and post
blocks, and therefore only one connection is needed. The italic renderer in the pre block sets its
continuation() to the italic renderer in the post block.
The function that performs the recursive splitting of inline flows and that creates the continuation
chain connections is called splitFlow and is in RenderInline.cpp.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
If the problem is having a block-level element within an inline element, then why is the
anonymous middle block necessary?
2. hyatt Says:
August 9th, 2007 at 4:48 pm
Strictly speaking it isn’t necessary, although it simplifies a lot of the code that deals with
continuations. It’s basically there for convenience.
3. hyatt Says:
August 9th, 2007 at 4:50 pm
Longer term, I’d like to explore eliminating continuations completely and wrapping the
offending blocks in an anonymous inline-block instead. The difficult problem with using
an anonymous inline-block, however, is that when the pre and post sections end up
having no content, you have to margin collapse the offending blocks with surrounding
content. This would necessitate having a sort of hybrid line/block layout that could easily
slide into and out of both layout modes.
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
When renderers are first created and added to the tree, they have no position or size yet. The
process by which all of the boxes have their positions and sizes determined is called layout. All
renderers have a layout method.
void layout()
Layout is a recursive operation. A class called FrameView represents the containing view for the
document, and it also has a layout method. The frame view is responsible for managing the
layout of the render tree.
There are two types of layout that the FrameView can perform. The first (and by far the most
common) is a layout of the entire render tree. In this case the root of the render tree has its layout
method called and then the entire render tree gets updated. The second type of layout is
constrained to a specific subtree of the render tree. It is used in situations where the layout of
some small subtree can’t possibly affect its surroundings. Right now the subtree layout is only
used by text fields (but may be used by overflow:auto blocks and other similar constructs in the
future).
Layout uses a dirty bit system to determine whether an object actually needs a layout. Whenever
new renderers are inserted into the tree, they dirty themselves and the relevant links in their
ancestor chain. There are three unique bits that are used by the render tree.
The first bit is used when the renderer itself is dirty, and it can be queried using the method
selfNeedsLayout. Whenever this bit is set to true, relevant ancestor renderers have bits set
indicating that they have a dirty child. The type of bit set depends on the positioned status of the
previous link in the chain being dirtied. posChildNeedsLayout is used to indicate that a
positioned child got dirtied. normalChildNeedsLayout is used to indicate that an in-flow child
got dirtied. By distinguishing between these two types of children, layout can be optimized for
the case where only positioned elements moved.
What exactly did I mean by “the relevant ancestor chain”? When an object is marked as needing
layout, the ancestor chain that is dirtied is based on a CSS concept called the containing block.
The containing block is also used to establish the coordinate space of children. Renderers have
xPos and yPos coordinates, and these are relative to their containing blocks. So what exactly is a
containing block?
My own way of introducing the concept in terms of the WebCore render tree would be as
follows:
A renderer’s containing block is an ancestor block of the renderer that is responsible for
determining that renderer’s position.
In other words when layout recurs down the render tree, it is a block’s responsibility to position
all of the renderers that have it as their containing block.
The root of the render tree is called the RenderView, and this class corresponds to the initial
containing block according to CSS2.1. It is also the renderer that will be returned if the
renderer() method is called on the Document.
RenderView.h
The initial containing block is always sized to the viewport. In desktop browsers, this is the
visible area in the browser window. It is also always at position (0,0) relative to the entire
document. Here’s a picture illustrating where the initial containing block is positioned for a
document. The black bordered box represents the RenderView, and the grey box represents the
entire document.
If the document is scrolled, then the initial containing block will be moved offscreen. It is always
at the top of the document and sized to the viewport. One area of confusion that people often
have with the initial containing block is that they expect it to somehow be outside the document
and part of the viewport.
The root element’s renderer (i.e., the <html> element) will always have the RenderView as its
containing block.
If a renderer has a CSS position of relative or static, then the containing block will be the nearest
block-level ancestor in the render tree.
If a renderer has a CSS position of fixed, then the containing block will be the RenderView.
Technically the RenderView does not act as a viewport, so the RenderView has to adjust the
coordinates of fixed positioned objects to account for the document scroll position. It is simpler
to just let the RenderView act like a viewport containing block for this one case rather than
having a separate renderer just for the viewport.
If a renderer has a CSS position of absolute, then the containing block is the nearest block-level
ancestor with a position other than static. If no such ancestor exists, then the containing block
will be the RenderView.
The render tree has two convenience methods for asking if an object has a position of absolute,
fixed or relative. They are:
Throughout most of the code the term positioned refers to both absolute and fixed positioned
objects in CSS. The term relPositioned refers to relative positioned objects in CSS.
The render tree has a method for obtaining the containing block of a renderer.
When an object is marked as needing layout, it walks up a container chain setting either the
normalChildNeedsLayout bit or the posChildNeedsLayout bit. The isPositioned status of
the previous link in the chain determines what bit gets set. The container chain roughly
corresponds to the containing block chain, although intermediate inlines are still dirtied as well.
A different method called container is used instead of containingBlock to determine the
chain for dirtying because of this distinction.
void layoutIfNeeded()
All layout methods typically end with setNeedsLayout(false). It is important to clear dirty
bits on the renderer before leaving the layout method, so that future layout calls won’t
mistakenly think that the object is still dirty.
void layout()
{
ASSERT(needsLayout());
...
}
// Now the intrinsic height of the object is known because the children
are placed
// Determine the final height
...
setNeedsLayout(false);
}
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
The position property in CSS can be used to position an object relative to a specific containing
block. It has four values: ’static’, ‘absolute’, ‘fixed’ and ‘relative’. Static positioning is the
default and means that the object is just positioned using the normal rules of block and line
layout.
Relative Positioning
Relative positioning is exactly like static positioning except that the CSS left, top, right and
bottom properties can be used to apply a translation to the object. The isRelPositioned method
can be used to ask if a renderer is using relative positioning.
bool isRelPositioned() const
The translation offset that will be applied can be obtained using the following methods:
Relative positioning is literally nothing more than a paint-time translation. As far as layout is
concerned, the object is at its original position. Below is an example that uses relative
positioning to shift part of a line up by a few pixels. As you can see, the line lays out as though
the object was at the original position.
Fixed positioned objects are positioned relative to the viewport, i.e., the visible page area of your
browser window. Absolute positioned objects are positioned relative to the containing block,
which is the nearest enclosing ancestor block with a position other than ’static’. If no such block
exists, then the initial containing block (the RenderView) is used. For more details on containing
blocks, see the previous article.
The isPositioned method can be used to find out if a renderer is absolute or fixed positioned.
When an object is absolute/fixed positioned, it becomes block-level. Even if the CSS display
type is set to inline (or inline-block/table), the effective display type becomes block-level once
an object is positioned. The isInline method will return false for positioned elements.
The RenderStyle can give both display values. There are times where the original display type
is relevant and needed by layout, and the following methods can be used to obtain both display
types.
Every block has a positioned objects list that contains all of the absolute/fixed positioned
renderers for which it is the containing block. It is the block’s responsibility to place these
positioned children. The following methods can be used to manipulate the positioned objects list:
void insertPositionedObject(RenderObject*);
void removePositionedObject(RenderObject*);
The layoutOnlyPositionedObjects method is used to lay out only the positioned objects for a
block. If only positioned objects changed, then this method returns true. This indicates that the
layout method doesn’t have to lay out any of its normal children and can just return early.
bool layoutOnlyPositionedObjects
The coordinates of positioned objects in CSS are relative to the padding edge of the containing
block. For example specifying a left and top position of (0, 0) for an absolute positioned object
will result in the object being placed just inside the containing block’s top left border. Here is an
example:
In WebCore, coordinate positions are always relative to the border edge, so in the above
example, the object is actually at (5, 5).
When the desired coordinates are omitted from CSS, WebCore has to determine an appropriate
place for the positioned object. CSS has a set of extremely complex rules for this, which we will
delve into in more detail in future articles.
It is possible for a relative positioned inline to act as a “containing block” for an absolutely
positioned descendant. This is another extremely complex edge case that warrants its own article.
For now it is enough to know that such a construct is possible, and that the code does have to
deal with it.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
A float is a renderer that is designed to shift all the way to the left side or all the way to the right
side of a paragraph. The lines of the paragraph then flow around the floating object avoiding it.
You can see an example of a float in this very paragraph. There is a purple box in the upper right
hand corner. Note how all of the text in this paragraph is avoiding the float.
There are also HTML constructs that imply CSS floating behavior. For example, the align
attribute on the img element can be used to float an image.
A float can span multiple paragraphs. In this example, even though the float was declared inside
this paragraph, it is tall enough that it will protrude out of this paragraph and into the next one.
Because floats can effectively intersect multiple blocks, WebCore uses a floating objects list on
block flows to track all of the floating renderers that intrude into the bounds of that block. A
single float can therefore be in the floating objects lists of multiple block flows. Line layout has
to be aware of the positions of floats so that it can make sure to shrink lines as necessary to avoid
these floats. By having all of the relevant floats for a given block immediately accessible in this
floating objects list, it becomes easy for that block to know where the floats are that it needs to
avoid.
FloatingObject(Type type)
: node(0)
, startY(0)
, endY(0)
, left(0)
, width(0)
, m_type(type)
, noPaint(false)
{
}
RenderObject* node;
int startY;
int endY;
int left;
int width;
unsigned m_type : 1; // Type (left or right aligned)
bool noPaint : 1;
};
As you can see, this structure effectively contains a rectangle (a top, bottom, left and width). The
reason each list entry has its own position and size that is independent of the floating object’s
position and size is that these coordinates are in the space of the block that owns the floating
objects list. This way each block can easily query for the float’s position in its own coordinate
space without having to do a bunch of conversions.
In addition the margins of the float are included in the list entry rectangles, since lines don’t just
avoid the border box of the float. They avoid the margin box of the float. This is important so
that floats can be padded with extra space to avoid having lines run right up to their edges.
void insertFloatingObject(RenderObject*);
void removeFloatingObject(RenderObject*);
void clearFloats();
void positionNewFloats();
The first two functions are pretty self-explanatory. They are used to add and remove specific
floats from a block’s floating objects list. clearFloats will delete all of the objects in a block’s
floating objects list.
When an object gets inserted into the list it is unpositioned initially. Its vertical position is set to
-1. The positionNewFloats method is called by layout to place all of the floats. CSS has a
bunch of rules for where floats are allowed to go. It is this method that ensures that all of those
rules are obeyed.
There are many more helper methods for working with floats. I will cover these when I talk
about block and line layout in more detail in future articles.
Clearance
CSS provides a way for objects to specify that they should be below either all left floats, all right
floats, or all floats. The clear property specifies this behavior and has values of none, left, right
or both.
This paragraph is below the blue float from the previous paragraph because it specified clear: left.
Clearance is computed and applied during block and line layout. The clear property can also be applied
to floats to make sure that a float ends up below all previous floats (again, either left, right or both types
of floats).
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
1. RichB Says:
August 16th, 2007 at 1:28 am
I’m surprised the concept of the Block Formatting Context wasn’t mentioned during the
Clearance discussion. This is one of the least known about concepts in CSS and yet it is
vitally important when writing stylesheets in order to isolate one visual style from
another.
Hint: Clearance isn’t just about a clear:left CSS property. It can also be achieved by
leaving a block formatting context.
2. hyatt Says:
August 16th, 2007 at 2:32 am
These initial articles are merely overviews, and are not intended to delve deeply into any
one topic yet.
[...] Dave Hyatt has posted five detailed articles on WebCore rendering. [...]
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
Before WebKit can render a web page, it needs to load the page and all of its subresources from
the network. There are many layers involved in loading resources from the web. In this post, I’ll
focus on explaining how WebCore, the main rendering component of WebKit, is involved in the
loading process.
WebKit contains two loading pipelines, one for loading documents into frames and another for
loading the subresources (such as images and scripts). The diagram below summarizes the major
objects involved in the two pipelines:
Loading Frames
The FrameLoader is in charge of loading documents into Frames. Whenever you click a link, the
FrameLoader begins by creating a new DocumentLoader object in the “policy” state, where it
awaits a decision by the WebKit client about how it should handle this load. Typically, the client
will instruct the FrameLoader to treat the load as a navigation (instead of blocking the load, for
example).
Once the client instructs the FrameLoader to treat the load as a navigation, the FrameLoader
advances the DocumentLoader to the “provisional” state, which kicks off a network request and
waits to determine whether the network request will result in a download or a new document.
The DocumentLoader, in turn, creates a MainResourceLoader, whose job is to interact with the
platform’s network library via the ResourceHandle interface. Separating the
MainResourceLoader from DocumentLoader serves two purposes: (1) the MainResourceLoader
insulates the DocumentLoader from details of handling the callbacks from the ResourceHandle
and (2) the lifetime of the MainResourceLoader is decoupled from the lifetime of the
DocumentLoader (which is tied to the Document).
Once the loading system has received sufficient information from the network to determine that
the resource actually represents a document, the FrameLoader advances the DocumentLoader to
the “committed” state, which transitions the Frame to displaying the new document.
Loading Subresources
Of course, displaying a web page requires more than just the HTML that comprises the
document. We also need to load the images, scripts, and other subresources referenced by the
document. The DocLoader is in charge of loading these subresources. (Note that although
DocumentLoader and DocLoader have similar names, their roles are quite different.)
Let’s take loading an image as a typical example. To load an image, the DocLoader first asks the
Cache whether it already has a copy of the image in memory (as a CachedImage object). If the
image is already in the Cache, the DocLoader can respond immediately with the image. For even
greater efficiency, the Cache often keeps the decoded image in video memory so that WebKit
does not have to uncompress the same image twice.
If the image is not in the Cache, the Cache creates a new CachedImage object to represent the
image. The CachedImage object asks the “Loader” object to kick off a network request, which
the Loader does by creating a SubresourceLoader. The SubresourceLoader plays a similar role in
the subresource loading pipeline as the MainResourceLoader does in the main resource loading
pipeline in that it interacts most directly with the ResourceHandle interface to the platform.
There are many areas in which we can improve WebKit’s loading pipelines. The FrameLoader is
significantly more complex than necessary and encompasses more tasks than simply loading a
frame. For example, FrameLoader has a several subtly different methods named “load,” which
can be confusing, and is responsible for creating new windows, which seems only tangentially
related to loading a frame. Also, the various stages of the loading pipeline are more tightly
coupled than necessary and there are a number of “layering” violations in which a lower-level
object interacts directly with a higher-level object. For example, the MainResourceLoader
delivers bytes received from the network directly to FrameLoader instead of delivering them to
DocumentLoader.
If you study the diagram above, you will notice that the Cache is used only for subresources. In
particular, main resource loads do not get the benefits of WebKit’s memory cache. If we can
unify these two loading pipelines, we might be able to improve the performance of main resource
loads. Over time, we hope to improve the performance of the loader to make loading web pages
as fast as possible.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
1. tomwang Says:
April 22nd, 2010 at 1:33 am
Can you please provide some overall code pieces about this process?
2. smkolins Says:
April 22nd, 2010 at 5:57 am
Hi. While I use Webkit I’m not so much a programmer. I found that at least with the
current Webkit I cannot comment on blogspot.com websites. It works in Safari 4.0.5 and
Firefox but not in the current nightly build. I know it should be a bug report but the
qualificiations for such reporting seem to be beyond me as I’m not so much a
programmer.
3. smkolins Says:
April 22nd, 2010 at 6:04 am
I checked with r58082 and it still doesn’t work. See for example
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
This is the first of two posts that will center around a modern browser engine feature that doesn’t
usually get a lot of press: The Page Cache.
Today I’ll talk a bit about what this feature is, why it often doesn’t work, and what plans we have
to improve it.
Some of you might be more familiar with what other browsers call their Page Cache. Firefox
calls theirs the “Back-Forward Cache” or “bfcache.” Opera refers to theirs as “Fast History
Navigation.” We’ve recently started to refer to WebKit’s implementation as the “Page Cache” to
reduce confusion with our “Back/Forward List.”
Note that the Page Cache is an end user feature that makes navigating the web much smoother. It
is not a “cache” in the “HTTP sense“. It is not a “cache” in the “disk cache” sense where raw
resources are stored on the local disk. And it’s not a “cache” in the traditional “memory cache”
sense where WebKit keeps decoded resources around in memory to be shared between multiple
web pages.
Quite simply, the Page Cache makes it so when you leave a page we “pause” it and when you
come back we press “play.”
When a user clicks a link to navigate to a new page the previous page is often thrown out
completely. The DOM is destroyed, Javascript objects are garbage collected, plug-ins are torn
down, decoded image data is thrown out, and all sorts of other cleanup occurs.
When this happens and the user later clicks the back button it can be painful for them. WebKit
may have to re-download the resources over the network, re-parse the main HTML file, re-run
the scripts that dynamically setup the page, re-decode image data, re-layout the page, re-scroll to
the right position, and re-paint the screen. All of this work requires time, CPU usage, and battery
power.
Ideally the previous page can instead be placed in the Page Cache. The entire live page is kept in
memory even though it is not on screen. This means that all the different bits and pieces that
represent what you see on the screen and how you interact with it are suspended instead of
destroyed. They can then be revived later in case you click the back button.
When the Page Cache works it makes clicking the back button almost instantaneous.
You can do a search, click a search result, then go back and immediately be looking at the exact
same results page. You might be browsing an aggregator site like Reddit or Digg and want to
rapidly view a lot of different links in the same tab. You might be navigating an image gallery
and decide to compare two images by alternately clicking “back” and “forward” rapidly. Or you
might have simply clicked on the wrong link and want to go back to correct your mistake.
Anytime you might click the back button or the forward button you unknowingly hope the Page
Cache is on your side. When the Page Cache is used, users are happy even though they’re not
aware of the magic behind the scenes.
Conversely, when the Page Cache is bypassed, users often get frustrated with both the browser
and the Web in general.
So if the Page Cache is so amazing, why doesn’t WebKit always use it when you navigate to a
new page?
First off, sometimes it doesn’t make sense to cache a page because it’s not interesting to return to
in the exact same state. For example, the page might not even be finished loading yet. Or the
page might’ve had an error loading. Or maybe the page was a redirection page that exists solely
to automatically move the user to some new URL.
These are cases where we’re happy with the current Page Cache behavior in WebKit.
Secondly, a page might not be considered for the Page Cache because it’s difficult to figure out
how to “pause” it. This happens with more complex pages that do interesting things.
For example, plug-ins contain native code that can do just about anything it wants so WebKit
can’t “hit the pause button” on them. Another example is pages with multiple frames which
WebKit has historically not cached.
Distressingly, navigating around these more advanced pages would benefit the most from the
Page Cache.
Server administrators for HTTPS sites often have particular security concerns and are very
sensitive with regards to how browsers behave. For example, Financial institutions are often very
thorough in verifying each particular browser’s behavior before allowing it to be used by their
customers.
One area often focused on is back/forward behavior. Such institutions are – understandably –
very picky about the types of data left behind in the browser as a user navigates. As a result, in
an effort to err on the side of extreme caution, WebKit has disallowed all HTTPS sites from its
Page Cache since the very beginning.
A more fine grained approach might go a long way towards improving the user experience.
Planned Improvements
Clearly there’s some important cases we don’t handle and therefore plenty of room for
improvement.
WebKit’s Page Cache was originally written in 2002 before the very first Safari beta release. Its
capabilities reflected both the architecture of WebKit at the time and the landscape of the Web in
2002.
The Web of 2009 is a much different place and we need to bring the Page Cache up to par.
Fortunately this work is well underway.
For example, as of revision 48036 a major limitation was resolved and pages with frames are
now placed in the Page Cache. Browsing with the latest WebKit nightly always seems to “feel
faster” in ways you can’t quite put your finger on, and recently some of you might have been
experiencing this enhancement.
Plug-ins are the next huge one on our hit list. As I mentioned earlier, plug-ins can run whatever
native code they like so we can’t reliably hit the “pause” button on them.
Earlier versions of WebKit handled single-frame pages with some types of plug-ins. WebKit
would tear down the plug-in when leaving the page and restoring it when the user returned. But
as work continued on WebCore to make it faster and easier to port, this ability was lost.
Bug #13634 tracks getting this working again for all plug-ins on all pages.
Then there are HTTPS pages. We completely ban them now, but a more selective approach
should be able to benefit users as well as keep security-minded institutions happy.
Bug #26777 tracks allowing HTTPS pages to be cached unless their response headers include
“cache-control: no-store” or “cache-control: no-cache” which has become the canonical way for
a selective organization to secure your content.
If you have any other ideas for what else might be improved, please feel free to comment in the
appropriate bug or file a new bug of your own!
Unload Handlers
The unload event was designed to let a page do some cleanup work when the user closes the
page.
The browser can’t fire the unload event before it puts the page in the Page Cache, because the
page then assumes it is in a terminal state and might destroy critical parts of itself. This
completely defeats the purpose of the Page Cache.
But if the browser puts the page in the Page Cache without running the unload handler, then the
page might be destroyed by the browser while it is “paused” and hidden, and that cleanup work –
which might be very important – will never happen.
Since the unload event’s purpose is to allow “important work when a page is closed,” all major
browsers refuse to put such pages in their Page Cache, causing a direct negative impact on the
user experience.
In a future post I’ll be talking more about unload event handlers and there will actually be
homework for many of you web developers out there! Stay tuned…
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
1. Miles Says:
September 16th, 2009 at 9:44 pm
Spoilers: https://bugs.webkit.org/show_bug.cgi?id=29021
2. CyberSkull Says:
September 17th, 2009 at 1:51 am
Hmm, perhaps what we need is something like a cache handler for JS and plugins; Ideally
to do whatever cleanup or state changes for going into cache and coming out of it…
CyberSkull, you’re exactly right and I strongly recommend you keep your eyes out for
part 2.
4. jomohke Says:
September 18th, 2009 at 4:55 am
It’s fantastic to see the return of technical articles detailing the innards of webkit. They
stopped appearing when this blog moved from just David Hyatt to an official team blog.
Please give us more!
6. kangax Says:
September 18th, 2009 at 7:48 pm
What’s even more disappointing is that we use browser sniffing as it seems impossible to
feature test this quirk. I suppose disabling unload in newer WebKit wouldn’t affect
Prototype, as long as document state persists properly (and it does in newer versions).
I would also love to hear if there’s a saner work around for this issue (i.e. any kind of
inference we can perform, to replace fragile `userAgent` parsing).
7. kangax Says:
September 18th, 2009 at 7:48 pm
8. nhoel Says:
September 20th, 2009 at 4:50 am
thanks,
-Nhoel of http://keywordspeak.com/?p=1234
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
Previously I touched on what exactly the Page Cache does and outlined some of the
improvements we’re working on.
This post is geared towards web developers and is therefore even more technical than the last.
In this article I’d like to talk more about unload event handlers, why they prevent pages from
going into the Page Cache, and what can be done to make things better.
Web developers can make use of the load and unload events to do work at certain points in the
lifetime of a web page.
The purpose of the load event is quite straightforward: To perform initial setup of a new page
once it has loaded.
The unload event is comparatively mysterious. Whenever the user leaves a page it is “unloaded”
and scripts can do some final cleanup.
The mysterious part is that “leaving the page” can mean one of a few things:
1. The user closes the browser tab or window, resulting in the destruction of the visible page.
2. The browser navigates from the old page to a new page, resulting in the destruction of the old
visible page.
The Page Cache makes this even more interesting by adding a new navigation possibility:
3. The browser navigates from the old page to a new page, but the old visible page is suspended,
hidden, and placed in the Page Cache.
Unload event handlers are meant to do some final cleanup when the visible page is about to be
destroyed. But if the page goes into the Page Cache it becomes suspended, is hidden, and is not
immediately torn down. This brings up interesting complications.
If we fire the unload event when going into the Page Cache, then the handler might be
destructive and render the page useless when the user returns.
If we fire the unload event every time a page is left, including each time it goes into the Page
Cache and when it is eventually destroyed, then the handler might do important work multiple
times that it was critical to only do once.
If we don’t fire the unload event when going into the Page Cache, then we face the possibility
that the page will be destroyed while it is suspended and hidden, and the unload handler might
never be run.
If we don’t fire the unload event when going into the Page Cache but consider firing it whenever
the suspended page is eventually destroyed, then we’re considering the possibility of doing
something that’s never been done before: Executing scripts that belong to an invisible web page
that has had its “pause” button pressed.
There’s all sorts of obstacles in making this work well including technological hurdles, security
concerns, and user-experience considerations.
Since there is no clear solution for handling such pages the major browsers vendors have all
come to the same conclusion: Don’t cache these pages.
Web developers have a few things they can do to help their pages be cacheable.
One is to only install the unload event handler if the code is relevant to the current browser. For
example, we’ve seen unload handlers similar to the following:
function unloadHandler()
{
if (_scriptSettings.browser.isIE) {
// Run some unload code for Internet Explorer
...
}
}
In all browsers other than Internet Explorer this code does nothing, but its mere existence
potentially slows down their user experience. This developer should’ve done the browser check
*before* installing the unload handler.
Another way developers can improve things is to only install the unload event handler when the
page has a need to listen for it, then remove it once that reason has passed.
For example the user might be working on a draft of a document so the developer installs an
unload handler to make sure the draft gets saved before the page is left. But they also start a
timer to automatically save it every minute or so. If the timer fires, the document draft is saved,
and the user doesn’t make any further changes, the unload handler should be removed.
Some time ago Mozilla approached this problem differently by inventing a replacement for
load/unload events.
The load and unload events are meant to be fired exactly once, and this is the underlying cause of
the problem. The pageshow/pagehide events – which we’ve implemented in WebKit as of
revision 47824 – address this.
Despite their name the pageshow/pagehide events don’t have anything to do with whether or not
the page is actually visible on the screen. They won’t fire when you minimize the window or
switch tabs, for example.
What they do is augment load/unload to work in more situations involving navigation. Consider
this example of how load/unload event handlers might be used:
<html>
<head>
<script>
function pageLoaded()
{
alert("load event handler called.");
}
function pageUnloaded()
{
alert("unload event handler called.");
}
</script>
<body>
<a href="http://www.webkit.org/">Click for WebKit</a>
</body>
</html>
Click here to view this example in a new window, in case you can’t guess what it does.
Try clicking the link to leave the page then press the back button. Pretty straightforward.
The pageshow/pagehide fire when load/unload do, but also have one more trick up their sleeve.
Instead of firing only at the single discrete moment when a page is “loaded” the pageshow event
is also fired when pages are restored from the Page Cache.
Similarly the pagehide event fires when the unload event fires but also when a page is suspended
into the Page Cache.
By including an additional property on the event called “persisted” the events tell the page
whether they represent the load/unload events or saving/restoring from the Page Cache.
<html>
<head>
<script>
function pageShown(evt)
{
if (evt.persisted)
alert("pageshow event handler called. The page was just restored
from the Page Cache.");
else
alert("pageshow event handler called for the initial load. This
is the same as the load event.");
}
function pageHidden(evt)
{
if (evt.persisted)
alert("pagehide event handler called. The page was suspended and
placed into the Page Cache.");
else
alert("pagehide event handler called for page destruction. This
is the same as the unload event.");
}
</script>
<body>
<a href="http://www.webkit.org/">Click for WebKit</a>
</body>
</html>
Click here to view this example in a new window, but make sure you’re using a recent WebKit
nightly.
Remember to try clicking the link to leave the page then press the back button.
1. It enables web developers to distinguish between a page being suspended and one that is being
destroyed.
2. When used instead of the unload event, it enables browsers to use their page cache.
It’s also straightforward to change existing code to use pagehide instead of unload. Here is an
example of testing for the onpageshow attribute to choose pageshow/pagehide when supported,
falling back to load/unload when they’re not:
<html>
<head>
<script>
function myLoadHandler(evt)
{
if (evt.persisted) {
// This is actually a pageshow event and the page is coming out
of the Page Cache.
// Make sure to not perform the "one-time work" that we'd
normally do in the onload handler.
...
return;
}
function myUnloadHandler(evt)
{
if (evt.persisted) {
// This is actually a pagehide event and the page is going into
the Page Cache.
// Make sure that we don't do any destructive work, or work that
shouldn't be duplicated.
...
return;
}
if ("onpagehide" in window) {
window.addEventListener("pageshow", myLoadHandler, false);
window.addEventListener("pagehide", myUnloadHandler, false);
} else {
window.addEventListener("load", myLoadHandler, false);
window.addEventListener("unload", myUnloadHandler, false);
}
</script>
<body>
Your content goes here!
</body>
</html>
Piece of cake!
To reiterate, we’ve now identified three great ways web developers can help the Page Cache
work better:
1. Only install the event handler if the code is relevant to the current browser.
2. Only install the event handler once your page actually needs it.
3. If supported by the browser, use pagehide instead.
Web developers that willfully ignore any or all these options are primarily accomplishing one
thing:
Forcing their users into “slow navigation mode.”
I say this both as a browser engineer and a browser user: That stinks!
But now that we’ve covered what savvy and polite web developers can do to help in the future,
we need to further scrutinize the current state of the web.
Browsers treat the unload handler as sacred because it is designed to do “important work.”
Unfortunately many popular sites have unload event handlers that decidedly do not “do
important work.” I commonly see handlers that:
Always update some cookie for tracking, even though it’s already been updated.
Always send an XHR update of draft data to a server, even though it’s already been sent.
Do nothing that could possible persist to any future browsing session.
That are empty. They literally do nothing.
Since these misbehaved pages are very common and will render improvements to WebKit’s Page
Cache ineffective a few of us started to ask the question:
What *would* actually happen if we simply started admitting these pages to the Page Cache
without running the unload event handler first?
Can we detect any patterns to determine whether an unload event handler is “important” or not?
Our Experiment
What this means for users is that their navigation experience could be noticeably smoother and
quicker in the common case. What this means for developers is that we’re consciously deciding
not to run some of their code and their web application might break.
For users and developers alike – Please leave your feedback, observations, or suggestions in the
bug tracking this experiment.
And remember this is just an experiment. No one is planning to ship this drastic change in
behavior in a production product. But the Page Cache is such an important part of browser
performance that we’re willing to push the envelope a little to improve it a lot.
We want to learn what breaks. We want to know if we can heuristically determine if an unload
handler is truly critical or not. We want to know if we can detect certain patterns in some types
of unload handlers and treat them differently. And, perhaps most importantly, we want to
evangelize.
At least one popular Javascript library has already adopted some of the advice we’ve given to
help improve the landscape on the web. If just a few more developers for popular sites or
libraries take notice of this experiment and change their code then the web will be a much
friendlier place for all of us.
You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings
are currently closed.
1. doekman Says:
September 22nd, 2009 at 2:22 am
BBC Glow has avoided adding an unload listener since 1.6 to avoid breaking this cache.
Also, (and webkit may do this already) you need to make sure the element that the mouse
is currently over has its mouseout event fired, else you might get sticky hover effects.
Jake.
To fire the unload event whenever the suspended page is eventually destroyed could be a
good idea. I don’t think executing scripts in an invisible page is a problem, since the
ability of executing scripts in the background can bring other potential benefits in the
future.
4. randallfarmer Says:
September 25th, 2009 at 12:28 am
As a user, I like more aggressive page caching. One approach might be to look for a
small class of onunload handlers that are generally safe to ignore, like Prototype’s and
empty handlers.
As a Web developer, I’ve sometimes specifically wanted to turn off the back/forward
cache. For example, I sometimes have an onsubmit handler — not an onunload! — that
leaves the page in an unusable state, e.g., by disabling the submit button. (That means my
form is broken if the user starts to submit then immediately hits Esc.)
When the user hits Back, I’d rather they see the page as it was at load time (but with form
data filled in), not as it was after submit. In an ideal world, I’d want them to see the page
as it was just before they hit Submit, but that’s not feasible to do.
Right now, I avoid the page cache by adding an empty onunload handler to disable the
page cache, but that will break. As alternatives, I could add a cache-control header, or
call window.location.reload() in onpageshow if evt.persisted. Both approaches have the
downside of forcing the page’s HTML to be redownloaded as well as skipping the page
cache. What do you all think is the best thing to do if I want to opt out of the page cache
but am OK with the browser using the cached HTML?
I know there are more elegant options than opting out of the page cache, like just not
messing with the form in my onsubmit handler or “fixing” the form in onpageshow. Still,
it seems interesting to ponder what to do if you want to opt out of the page cache; surely
someone out there will.
If there were some other programatic way to disable the PageCache, that would still be
desirable to the unload handler. Semantically, the “unload handler” and “I want to disable
the PageCache!” are two completely different things.
Of course, maybe that wouldn’t be much different than the situation today…
6. randallfarmer Says:
September 25th, 2009 at 2:31 pm
@Brady:
In my defense, the pages I’m thinking of are essentially one big form, and if you leave
the page, you’re usually either submitting or never coming back (e.g., closing the
window). The onunload is there full-time for these pages right now (I might fix!), but
navigating away without submitting and then coming back is rare enough that slowing
down that case is bearable, if sloppy.
You’re also right that we’ll inevitably sometimes use it in ways that make the page
slower than is strictly necessary — sorry. Browser developers put up with a lot of
nonsense from Web developers — we owe you one. Or rather, we owe you many many.
Home
Surfin’ Safari Blog
Planet WebKit
Project Goals
Keeping in Touch
Trac
Contributors Meeting
Working with the Code
Installing Developer Tools
Getting the Code
Building WebKit
Running WebKit
Debugging WebKit
Contributing Code
Commit and Review Policy
Security Policy
Documentation
Wiki
Projects
Code Style Guidelines
Technical Articles
Web Inspector
Web Developer Resources
Demos
Testing
Regression Testing
Leak Hunting
Writing New Tests
Getting a Crash Log
Bugs
Reporting Bugs
Bug Report Guidelines
Bug Prioritization
Test Case Reduction
Bug Life Cycle
Archives
March 2011
February 2011
January 2011
December 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
December 2008
October 2008
September 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
December 2006
November 2006
October 2006
September 2006
August 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
WebKit is open source software with portions licensed under the LGPL and BSD licenses. Complete
license and copyright information can be found within the code.
Hosting provided by Mac OS Forge. Use of this site is subject to the Mac OS Forge Terms of Use.
Surfin' Safari site is powered by WordPress
Entries (RSS) and Comments (RSS).
Register | Log in
This diagram illustrates how it happens, showing relationships between the objects involved.