<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Surfin' Safari</title>
	<atom:link href="http://webkit.org/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://webkit.org/blog</link>
	<description>All about WebKit development</description>
	<lastBuildDate>Fri, 06 Nov 2009 06:23:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Web Inspector Updates</title>
		<link>http://webkit.org/blog/829/web-inspector-updates/</link>
		<comments>http://webkit.org/blog/829/web-inspector-updates/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 02:13:28 +0000</pubDate>
		<dc:creator>Joseph Pecoraro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=829</guid>
		<description><![CDATA[A number of exciting new features have been added to the Web Inspector since our last update. Today we would like to highlight some of those features! This post is also available in Japanese (日本語), thanks to Keishi Hattori (服部慶士).
If you would like to play with most of these features you will need to be [...]]]></description>
			<content:encoded><![CDATA[<p>A number of exciting new features have been added to the Web Inspector since our <a href="/blog/197/web-inspector-redesign/">last update</a>. Today we would like to highlight some of those features! This post is also available in <a href="http://trac.webkit.org/wiki/Web%20Inspector%20Update.ja">Japanese (日本語)</a>, thanks to Keishi Hattori (服部慶士).</p>
<p>If you would like to play with most of these features you will need to be running a recent <a href="http://nightly.webkit.org/">WebKit Nightly</a>. Once downloaded make sure that you enable the Web Inspector by checking “Show Develop menu in menu bar” under the Advanced tab in the Preferences.</p>
<p><a class="image" href="/blog-files/inspector/enable.png"><img src="/blog-files/inspector/enable.png" alt="Enabling the Inspector in Preferences" /></a></p>
<h3 id="editing">Editing Element Attributes and Style Properties <a href="#editing">#</a></h3>
<p>Editing Element Attributes and Style Properties has been made even simpler and more developer friendly. The interfaces for editing attributes and properties now support tabbing to allow you to move between items, and create new items with ease.</p>
<p>Besides tabbing you can also add a new attributes to a node.  Start by hovering over the node in the Element’s Tree Hierarchy and after a polite wait a clickable template for a new attribute will appear.</p>
<p><a class="image" href="/blog-files/inspector/edit_attributes.png"><img src="/blog-files/inspector/edit_attributes.png" alt="Edit Element Attributes" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=21108">Add Element Attributes</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27673">Tabbing</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30057">Improved UI</a>.</p>
<h3 id="css_selectors">Creating and Modifying CSS Rules and Selectors <a href="#css_selectors">#</a></h3>
<p>A powerful new feature in the Web Inspector allows you create new or modify existing CSS Rules and Selectors. We expect both developers and designers will find this very useful when experimenting with new ideas or tweaking existing designs.</p>
<p>The interface for working with selectors starts with a new Gear Menu in the Styles Sidebar Pane. Select “New Style Rule” and a new section will be created for you, pre-populated with an intelligent selector from the selection in the Elements Tree Hierarchy. Editing selectors is activated by double-clicking. Once again, tabbing will allow you to navigate between selectors and their properties.</p>
<p>When editing selectors there is visual feedback when you create or modify a selector that does not affect the selected node in the Elements Tree Hierarchy. This indicator helps detect errors when making changes.</p>
<p><a class="image" href="/blog-files/inspector/css_selectors.png"><img src="/blog-files/inspector/css_selectors.png" alt="Create and Modify CSS Selectors" /></a></p>
<p>One more tweak to the Styles Pane is that there is always a section for the selected node’s style attribute. This allows you to easily add style information to the node as you usually would via the Styles Pane instead of editing or creating a “style” attribute. This section is nearly always on top due to how CSS specificity works.</p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27124">Selectors Support</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=29039">Move to Gear Menu</a>.</p>
<h3 id="colors">CSS Color Representations <a href="#colors">#</a></h3>
<p>Colors in the Styles Pane can be shown in any of their possible representations. For simple colors this includes short hex, full hex, rgb, hsl, and potentially a nickname. For advanced colors this includes rgba and hsla. For example the color “white” can be represented as: <code>#FFF</code>, <code>#FFFFFF</code>, <code>rgb(255, 255, 255)</code>, <code>hsl(0, 100%, 100%)</code>, and <code>white</code>.</p>
<p>You can use the Styles Pane’s Gear Menu to set your preferred representation. However, if you want to cycle through an individual color’s different representations you can do so by clicking on its associated color swatch.</p>
<p><a class="image" href="/blog-files/inspector/colors.png"><img src="/blog-files/inspector/colors.png" alt="Mutiple Color Representations" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=13516">Color Representations</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=28889">Preference and Gear Menu</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=28978">UI Improvement</a>.</p>
<h3 id="dom_storage">DOM Storage <a href="#dom_storage">#</a></h3>
<p>The Storage Panel (formerly the Databases Panel) now allows you to monitor DOM Storage areas like <code>localStorage</code> and <code>sessionStorage</code> in a familiar datagrid. The DOM Storage datagrid displays live updates so monitoring changes is possible without manually refreshing the view.</p>
<p>Also, the familiar creation and editing techniques apply to the datagrid. To add a new key/value pair just double-click in any open area, or double-click an existing item to start editing. Tabbing works as you would expect.</p>
<p><a class="image" href="/blog-files/inspector/dom_storage.png"><img src="/blog-files/inspector/dom_storage.png" alt="Observing DOM Storage Key/Value Pairs" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=21051">DOM Storage Support</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27400">Live Updates</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27322">Create New Items</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27746">Tabbing</a>.</p>
<h3 id="keyboard_shortcuts">Keyboard Shortcuts <a href="#keyboard_shortcuts">#</a></h3>
<p>Keyboard shortcuts are always desired by developers. They can be hard to discover, so <a href="http://trac.webkit.org/wiki/Web%20Inspector#ShortcutKeys">here is a complete list</a> and here are the ones that were added recently:</p>
<ul>
<li><strong>Switch Panels</strong> — <span>Command-[</span> and <span>Command-]</span> on a Mac or <span>Control-[</span> and <span>Control-]</span> on other platforms.</li>
<li><strong>Delete a Node in the Tree Hierarchy</strong> — either <span>Delete</span> or <span>Backspace</span> keys will do the trick.</li>
<li><strong>Quick Edits in the Tree Hierarchy</strong> — Hitting <span>Enter</span> or <span>Return</span> on a Node in the Tree enters the editing mode for that type of Node.  For a Text Node you will start editing the content.  For Element Nodes you start editing the first attribute, or, for convenience, a new attribute will be added for you.</li>
</ul>
<p>The Scripts Debugger was updated to support some popular keyboard shortcuts:</p>
<ul>
<li><strong>Continue</strong> — <span>F8</span> or <span>Command-/</span> on a Mac or <span>Control-/</span> on other platforms.</li>
<li><strong>Step Over</strong> — <span>F10</span> or <span>Command-&#8217;</span> on a Mac or <span>Control-&#8217;</span> on other platforms.</li>
<li><strong>Step Into</strong> — <span>F11</span> or <span>Command-;</span> on a Mac or <span>Control-;</span> on other platforms.</li>
<li><strong>Step Out</strong> — <span>Shift-F11</span> or <span>Shift-Command-;</span> on a Mac or <span>Shift-Control-;</span> on other platforms.</li>
<li><strong>Next Call Frame</strong> — <span>Control-.</span> on all platforms.</li>
<li><strong>Previous Call Frame</strong> — <span>Control-,</span> on all platforms.</li>
<li><strong>Evaluate Selection When on a Breakpoint</strong> — <span>Shift-Command-E</span> on a Mac or <span>Shift-Control-E on other platforms.</span></li>
</ul>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27286">Switch Panels</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30337">Delete Node</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30428">Quick Edit</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=23849">General Debugger Shortcuts</a> and <a href="https://bugs.webkit.org/show_bug.cgi?id=27502">Evaluate Selection</a>.</p>
<h3 id="cookies">Cookies <a href="#cookies">#</a></h3>
<p>Viewing Cookie information is now possible under the Storage Panel. Supported platforms show all of the cookies and their hidden information for all domains accessed on the inspected page. Cookie information includes the name, value, path, expiration date, http only flag, and secure (https) flag. Supported platforms may also delete cookies.</p>
<p>If your platform doesn’t have full support you aren’t left in the dark. You will still be able to see the keys and values of the cookies that are accessible via JavaScript on the inspected page.</p>
<p><a class="image" href="/blog-files/inspector/cookies.png"><img src="/blog-files/inspector/cookies.png" alt="Inspect Hidden Cookie Information" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27202">Initial Support</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=28269">Hidden Data 1</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=28185">2</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30104">Cookies for Sub-Resources</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30036">UI Improvements</a></p>
<h3 id="event_listeners">Event Listeners <a href="#event_listeners">#</a></h3>
<p>A new Sidebar Pane has been added to the Elements Panel which displays the registered Event Listeners for the selected node.  The Event Listeners that are shown for the selected node are in the exact order that they are fired through the Capturing and Bubbling phases.  This provides developers with the most accurate and useful information possible.</p>
<p>The user interface shows the registered Event Listeners separated by type. If a node has both “onclick” and “onmouseover” listeners then they will naturally appear in different sections. You can also set your filter preference using the Gear Menu. You can choose to see only the listeners registered on the selected node, or the entire event flow.</p>
<p><a class="image" href="/blog-files/inspector/event_listeners.png"><img src="/blog-files/inspector/event_listeners.png" alt="Inspect Registered Event Listeners" /></a></p>
<p>We are actively looking for UI improvements in this area. So if you have some ideas or feedback please feel free to let us know on <a href="https://bugs.webkit.org/show_bug.cgi?id=29789">this bug report</a>!</p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=17429">Event Listeners</a>.</p>
<h3 id="syntax_highlighting">Syntax Highlighting <a href="#syntax_highlighting">#</a></h3>
<p>Syntax highlighting enhances readability, makes debugging code easier, and looks really awesome. The Web Inspector now includes syntax highlighting for JSON and CSS.</p>
<p><a class="image" href="/blog-files/inspector/css_syntax_highlight.png"><img src="/blog-files/inspector/css_syntax_highlight.png" alt="CSS Syntax Highlighting" /></a></p>
<p>CSS Syntax Highlighting even works on the more complex “at-rules” such as <code>@import</code>, <code>@media</code> and <code>@font-face</code>. In addition to supporting the syntax highlighting in the Resources Panel, inline scripts and styles in the Elements Tree Hierarchy are syntax highlighted!</p>
<p><a class="image" href="/blog-files/inspector/inline_highlight.png"><img src="/blog-files/inspector/inline_highlight.png" alt="Inline JavaScript and CSS Syntax Highlighting" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27503">JSON Highlighting</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=14359">CSS Highlighting</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30062">Inline Highlighting</a>.</p>
<h3 id="breakpoints">Breakpoints and Watch Expressions <a href="#breakpoints">#</a></h3>
<p>The Script Debugger continues to become more powerful and more useful.  We already mentioned the <a href="#keyboard_shortcuts">keyboard shortcuts</a> above, but there are plenty of other enhancements.</p>
<p><span style="background-color: #ffffff">There is a new Breakpoints Sidebar Pane that allows you to easily monitor and work with your breakpoints across all files without the hassle of searching for them.  Each sidebar entry shows the source line and contains a checkbox that allows you to directly enable or disable the breakpoint. Clicking on the entry will jump you directly to the highlighted line in the source file. Finally, deleting a breakpoint has been made easier by clicking the &#8220;blue tag&#8221; breakpoint indicator.  The tag will cycle through its three states of active, inactive, and removed.</span></p>
<p>A powerful feature added to the debugger is Conditional Breakpoints. Once you have a breakpoint set, right click on the &#8220;blue tag&#8221; breakpoint indicator and you will get a popup asking for a conditional statement for that breakpoint. Simply provide an expression and the breakpoint will only pause from then on only if the condition is true.</p>
<p><a class="image" href="/blog-files/inspector/breakpoints.png"><img src="/blog-files/inspector/breakpoints.png" alt="Breakpoints and other Debugging Improvements" /></a></p>
<p>Another new feature in the Debugger is Watch Expressions.  In this new Sidebar Pane you can add any number of expressions that evaluate in the global scope normally but in the local scope when paused in the debugger. Once added you get the full Object Properties tree view of the values of each expression.  These watch expressions automatically refresh when the debugger pauses. They are also persist across page loads.</p>
<p><a class="image" href="/blog-files/inspector/watched_expression.png"><img src="/blog-files/inspector/watched_expression.png" alt="Watched Expressions in Action" /></a></p>
<p>Related Bug Reports: <a href="https://bugs.webkit.org/show_bug.cgi?id=11175">Breakpoints Sidebar Pane</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27514">Watch Expressions</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27502">Evaluate on Breakpoint</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=28908">Conditional Breakpoints</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=19131">Delete Breakpoints</a>.</p>
<h3 id="ajax">Debugging AJAX <a href="#ajax">#</a></h3>
<p>An extremely valuable feature for developers working with AJAX is the ability to view the exact parameters and payload sent on XMLHttpRequests.</p>
<p>In the individual resource view there are new sections for viewing submitted Form Data, Query String Parameters, and Request Payloads when appropriate. You can toggle viewing the information in its unencoded (default) and encoded forms with a double-click.</p>
<p>There is also new section named HTTP Information which contains the Request Method (GET, POST, etc.) and the Status Code (200, 404, etc.). Additionally, it adds a colored dot next to the requested URL to show the status (green for success, orange for redirect, and red for error).</p>
<p><a class="image" href="/blog-files/inspector/form_data.png"><img src="/blog-files/inspector/form_data.png" alt="View Submitted Form Data and HTTP Information" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=19945">HTTP Status Code</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=22920">Data, Parameters, and Payload</a></p>
<h3 id="scope_bars">Resources and Console Scope Bars <a href="#scope_bars">#</a></h3>
<p>In order to filter through the Resources or Console messages the Web Inspector now sports some familiar Scope Bars. This has proven to be very useful in the Resources Panel for easily viewing all resources of a particular type.</p>
<p><a class="image" href="/blog-files/inspector/scope_bar.png"><img src="/blog-files/inspector/scope_bar.png" alt="Quick Filtering Scope Bars for Resources Types and Console Message Types" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=20629">Resources Scope Bar</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=29195">Console Scope Bars</a>.</p>
<h3 id="load_lines">Resources Timeline <a href="#load_lines">#</a></h3>
<p>The Web Inspector now specifically shows in the timeline when the DOMContentLoaded and Load events fire. This helps clarify the time it takes for pages to load and helps you improve your websites load times.</p>
<p><a class="image" href="/blog-files/inspector/load_lines.png"><img src="/blog-files/inspector/load_lines.png" alt="DOMContent Ready Event and Page's Load Event Indicators" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=14370">Show Load Lines</a></p>
<h3 id="resource_interactivity">Resources Interactivity <a href="#resource_interactivity">#</a></h3>
<p>A couple new features allow you to more directly access individual resources from within the Web Inspector. Instead of copying their URL and opening a new tab manually you can now double-click the Resource in the sidebar to open it directly in a new window. Or, you can drag and drop the resource using HTML5 drag and drop events!</p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=14409">Open Resource Directly</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=30079">Drag and Drop</a>.</p>
<h3 id="console_improvements">Console Improvements <a href="#console_improvements">#</a></h3>
<p>Properties in the Web Inspector’s Console are now sorted in a much more natural and useful way. By sorting keys alphanumerically Arrays with greater then 10 elements are much easier to work with.</p>
<p><a class="image" href="/blog-files/inspector/inorder.png"><img src="/blog-files/inspector/inorder.png" alt="Alphanumeric Sorting" /></a></p>
<p>Another tweak is that collections such as NodeLists and HTMLCollections are now displayed like Arrays.  This meaning that their contents are shown directly in the console, no longer requiring any extra boilerplate.</p>
<p><a class="image" href="/blog-files/inspector/nodelist.png"><img src="/blog-files/inspector/nodelist.png" alt="More Descriptive Nodelists" /></a></p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27329">Sorting</a> and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=28061">NodeLists</a>.</p>
<h3 id="firebug_api">Firebug Command API Improvements <a href="#firebug_api">#</a></h3>
<p>More improvements have been made to support more of the <a href="http://getfirebug.com/commandline.html">Firebug Command Line API</a>. The Web Inspector now supports the <code>inspect()</code> function, which can take an Element, Database, or Storage area and automatically jumps to the appropriate Panel with information. Also, the <code>$0</code>-<code>$4</code> variables contain the current and previous selected nodes from the Elements Tree Hierarchy.</p>
<p>These command line APIs are usable inside the Web Inspector’s Console. To make working with these APIs even easier, they now show up in the Console’s autocompletion.</p>
<p>Related Bug Reports: <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=17907">$# Variables</a>, <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=19874">inspect() Function</a>, and <a class="bug" href="https://bugs.webkit.org/show_bug.cgi?id=27696">Autocompletion</a>.</p>
<h3 id="contribute">How You Can Contribute <a href="#contribute">#</a></h3>
<p>Many of these new features were added by members of the Open Source Community. We would like to encourage you to contribute as well! Since the Web Inspector itself is mostly HTML, JavaScript, and CSS that means that you already have the skills you need to join in! Interested? Play around right now by inspecting the inspector itself!</p>
<p><a class="image" href="/blog-files/inspector/inspect_inspector.png"><img src="/blog-files/inspector/inspect_inspector_small.png" alt="Work on the Web Inspector using the Web Inspector!" /></a></p>
<p>If you’re interested in contributing and have any questions please stop by the <a href="irc://irc.freenode.net/#webkit-inspector">#webkit-inspector</a> IRC channel! As an encouragement to developers, included at the end of each section above are the core bug reports that were involved in bringing each of these features to life.</p>
<p>Finally, if you have ideas for new features, any improvements, or if you’ve stumbled across a bug then please don’t hesitate to create a bug report. <a href="http://webkit.org/new-inspector-bug">This link</a> has pre-populated most of the fields so that you only need to fill out the Summary and Description. As always you should do a quick search through the <a href="http://bit.ly/RDwz2">existing inspector bugs</a> first.</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/829/web-inspector-updates/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>WebGL Now Available in WebKit Nightlies</title>
		<link>http://webkit.org/blog/603/webgl-now-available-in-webkit-nightlies/</link>
		<comments>http://webkit.org/blog/603/webgl-now-available-in-webkit-nightlies/#comments</comments>
		<pubDate>Mon, 19 Oct 2009 20:55:20 +0000</pubDate>
		<dc:creator>Chris Marrin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=603</guid>
		<description><![CDATA[
Introduction

WebGL is a new standard being worked on in the Khronos consortium. The work done in Khronos is only available to its members, so I can&#8217;t show you the spec just yet. But it will become public within the next few months after a review by Khronos members. The good news is that WebGL is [...]]]></description>
			<content:encoded><![CDATA[<link rel="stylesheet" href="/blog-files/webgl/resources/blogpost.css" type="text/css" />
<h3>Introduction</h3>
<p>
WebGL is a new standard being worked on in the <a href="http://khronos.org">Khronos</a> consortium. The work done in Khronos is only available to its members, so I can&#8217;t show you the spec just yet. But it will become public within the next few months after a review by Khronos members. The good news is that WebGL is now available in <a href="http://nightly.webkit.org/">WebKit nightlies</a> as of October 4, 2009 (r49073). So if you&#8217;re running Leopard or Snow Leopard you can try it out for yourself. WebGL runs in the HTML Canvas element, so it works very similarly to the 2D Canvas capability currently in WebKit.
</p>
<h3>OpenGL for the Web</h3>
<p>
OpenGL has been around for ages, so it&#8217;s very mature. It can handle all the features of the most advanced graphics cards, but works across a wide variety of hardware. WebGL is based on OpenGL ES 2.0 which is a shader based API.
</p>
<p>
WebGL is a very low level API, so it&#8217;s not for the faint of heart. OpenGL&#8217;s shading language, GLSL, is itself an entire programming environment. So doing even simple things in WebGL takes a lot of code. You have to load, compile and link the shaders, setup <em>vertex buffer objects</em> to hold the shapes, and setup the variables to be passed into the shaders. Then you have to do matrix math to animate the shapes. If you want to learn more about all this before continuing, head over to the <a href="http://www.opengl.org/sdk/docs/tutorials/">OpenGL Site</a> for some nice tutorials.
</p>
<h3>Getting Started</h3>
<p>
WebGL is <em>really cool!</em> But because it&#8217;s new and still under development it isn&#8217;t turned on by default. To do that, you need to go into Terminal and type this:
</p>
<pre>
    defaults write com.apple.Safari WebKitWebGLEnabled -bool YES
</pre>
<p>
Once you&#8217;ve done that, restart the WebKit nightly build. Then click on the image below. If you see a spinning cube, you have WebGL installed and enabled. If not go back and make sure you have the latest Safari and you typed the above line correctly.
</p>
<p><a href="/blog-files/webgl/SpiritBox.html" style="text-decoration: none"><br />
<img src="/blog-files/webgl/resources/SpiritBox.jpg" alt="Image of Spinning Box" /></a><br />
<a href="/blog-files/webgl/SpiritBox.html"><br />
    Click to see Spinning Box (requires WebGL)<br />
</a></p>
<p>
If you don&#8217;t have a nightly build, you can still see WebGL in action <a href="http://www.youtube.com/watch?v=2rpKpj6ZO9w">here</a>.
</p>
<h3>A Simple Example</h3>
<p>
Let&#8217;s see how to create the spinning cube above. For the examples and demos here I&#8217;ve created a couple of files of JavaScript utilities to help out: one with some <a href="/blog-files/webgl/resources/utils3d.js">general utilities</a> and another with a set of <a href="/blog-files/webgl/resources/CanvasMatrix.js">matrix functions</a>. These will let us focus on the different steps needed to use WebGL without worrying about the details.
</p>
<p>
Like I said, WebGL is built on top of the Canvas Element. So just like you do for a 2D Canvas you start out by getting a CanvasRenderingContext with a call to the <code>getContext</code> method of the Canvas Element, passing the string &#8220;webkit-3d&#8221; (this is temporary, and will eventually change to &#8220;webgl&#8221;). The returned object has a set of functions very similar to OpenGL ES 2.0.
</p>
<h3>Using Shaders</h3>
<p>
Nothing happen in WebGL without shaders. They take shape data and turn it into pixels on the screen. When using GLSL you define two separate shaders. The <em>vertex shader</em> runs on each corner of every triangle being rendered. Here you transform the points, pass along the texture coordinates and use the normals to compute a lighting factor based on the <em>normals</em> of each triangle. There is a really nice <a href="http://www.lighthouse3d.com/opengl/glsl/index.php?lights">GLSL Tutorial</a> on lighting. GLSL gives you one special variable to store the transformed corner point, <code>gl_Position</code>. The value stored there for each of the corners of a triangle is used to interpolate all the pixels being output. The texture coordinates and lighting factor are passed in <em>varying</em> variables we created for the purpose.
</p>
<p>
All these values are passed to the <em> fragment shader</em>, which runs on each pixel of every transformed triangle passed in. This is where you get the appropriate pixel from the texture, adjust its lighting, and output the pixel. GLSL gives you a special variable for this, <code>gl_FragColor</code>. Whatever color your store there will be the color of that pixel.
</p>
<p>
So let&#8217;s define the shaders. I&#8217;ll use normal script notation here, even though HTML ignores it. It&#8217;s a useful way to include GLSL. The contents of the script will be passed as a string to the <code>shaderSource</code> function:
</p>
<div class="hlcode">
<div class="syntax">
<pre><span class="nt">&lt;script </span><span class="na">id=</span><span class="s">&quot;vshader&quot;</span><span class="na">type=</span><span class="s">&quot;x-shader/x-vertex&quot;</span><span class="nt">&gt;</span></pre>
</div>
<div class="syntax">
<pre>        <span class="k">uniform</span> <span class="k">mat4</span> <span class="nv">u_modelViewProjMatrix</span><span class="p">;</span>
        <span class="k">uniform</span> <span class="k">mat4</span> <span class="nv">u_normalMatrix</span><span class="p">;</span>
        <span class="k">uniform</span> <span class="k">vec3</span> <span class="nv">lightDir</span><span class="p">;</span>

        <span class="k">attribute</span> <span class="k">vec3</span> <span class="nv">vNormal</span><span class="p">;</span>
        <span class="k">attribute</span> <span class="k">vec4</span> <span class="nv">vTexCoord</span><span class="p">;</span>
        <span class="k">attribute</span> <span class="k">vec4</span> <span class="nv">vPosition</span><span class="p">;</span>

        <span class="k">varying</span> <span class="k">float</span> <span class="nv">v_Dot</span><span class="p">;</span>
        <span class="k">varying</span> <span class="k">vec2</span> <span class="nv">v_texCoord</span><span class="p">;</span>

        <span class="k">void</span> <span class="nv">main</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="nsv">gl_Position</span> <span class="o">=</span> <span class="nv">u_modelViewProjMatrix</span> <span class="o">*</span> <span class="nv">vPosition</span><span class="p">;</span>
            <span class="nv">v_texCoord</span> <span class="o">=</span> <span class="nv">vTexCoord</span><span class="p">.</span><span class="nv">st</span><span class="p">;</span>
            <span class="k">vec4</span> <span class="nv">transNormal</span> <span class="o">=</span> <span class="nv">u_normalMatrix</span> <span class="o">*</span> <span class="k">vec4</span><span class="p">(</span><span class="nv">vNormal</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
            <span class="nv">v_Dot</span> <span class="o">=</span> <span class="nv">max</span><span class="p">(</span><span class="nv">dot</span><span class="p">(</span><span class="nv">transNormal</span><span class="p">.</span><span class="nv">xyz</span><span class="p">,</span> <span class="nv">lightDir</span><span class="p">),</span> <span class="mf">0.0</span><span class="p">);</span>
        <span class="p">}</span>

<span class="nt">&lt;/script&gt;</span>

<span class="nt">&lt;script </span><span class="na">id=</span><span class="s">&quot;fshader&quot;</span> <span class="na">type=</span><span class="s">&quot;x-shader/x-fragment&quot;</span><span class="nt">&gt;</span>

        <span class="k">uniform</span> <span class="k">sampler2D</span> <span class="nv">sampler2d</span><span class="p">;</span>

        <span class="k">varying</span> <span class="k">float</span> <span class="nv">v_Dot</span><span class="p">;</span>
        <span class="k">varying</span> <span class="k">vec2</span> <span class="nv">v_texCoord</span><span class="p">;</span>

        <span class="k">void</span> <span class="nv">main</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">vec2</span> <span class="nv">texCoord</span> <span class="o">=</span> <span class="k">vec2</span><span class="p">(</span><span class="nv">v_texCoord</span><span class="p">.</span><span class="nv">s</span><span class="p">,</span> <span class="mf">1.0</span> <span class="o">-</span> <span class="nv">v_texCoord</span><span class="p">.</span><span class="nv">t</span><span class="p">);</span>
            <span class="k">vec4</span> <span class="nv">color</span> <span class="o">=</span> <span class="nv">texture2D</span><span class="p">(</span><span class="nv">sampler2d</span><span class="p">,</span><span class="nv">texCoord</span><span class="p">);</span>
            <span class="nv">color</span> <span class="o">+=</span> <span class="k">vec4</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">0.1</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
            <span class="nsv">gl_FragColor</span> <span class="o">=</span> <span class="k">vec4</span><span class="p">(</span><span class="nv">color</span><span class="p">.</span><span class="nv">xyz</span> <span class="o">*</span> <span class="nv">v_Dot</span><span class="p">,</span> <span class="nv">color</span><span class="p">.</span><span class="nv">a</span><span class="p">);</span>
        <span class="p">}</span>

<span class="nt">&lt;/script&gt;</span>
</pre>
</div>
<p>
The vertex shader in this example simply sends along the vertex position, <code>vPosition</code> to the fragment shader after transforming it by a composite model-view/projection matrix. We&#8217;ll get to that later. Then it passes along the texture coodinate, <code>vTexCoord</code>, and uses the normal in <code>vNormal</code> to compute a lighting factor, <code>v_Dot</code> for the fragment shader. The fragment shader is even simpler. It just gets a pixel from the texture, (after flipping the texture coordinate so the image is right-side up). Then multiplies that by the lighting factor passed in from the vertex shader. This causes the pixels to be brighter when a side of the cube is facing you and darker when it is at an angle, giving it a realistic lighting effect.
</p>
<h3>Initializing the Engine</h3>
<p>
    Now we have to get WebGL up and running. The utility library we first loaded will help us here:
</p>
<div class="hlcode">
<div class="syntax">
<pre>    <span class="kd">function</span> <span class="nx">init</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="c1">// Initialize</span>
        <span class="kd">var</span> <span class="nx">gl</span> <span class="o">=</span> <span class="nx">initWebGL</span><span class="p">(</span>
                <span class="c1">// The id of the Canvas Element</span>
                <span class="s2">&quot;example1&quot;</span><span class="p">,</span>
                <span class="c1">// The ids of the vertex and fragment shaders</span>
                <span class="s2">&quot;vshader&quot;</span><span class="p">,</span> <span class="s2">&quot;fshader&quot;</span><span class="p">,</span>
                <span class="c1">// The vertex attribute names used by the shaders.</span>
                <span class="c1">// The order they appear here corresponds to their index</span>
                <span class="c1">// used later.</span>
                <span class="p">[</span> <span class="s2">&quot;vNormal&quot;</span><span class="p">,</span> <span class="s2">&quot;vTexCoord&quot;</span><span class="p">,</span> <span class="s2">&quot;vPosition&quot;</span><span class="p">],</span>
                <span class="c1">// The clear color and depth values</span>
                <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span> <span class="p">],</span> <span class="mi">10000</span><span class="p">);</span>

        <span class="c1">// Set some uniform variables for the shaders</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">uniform3f</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">getUniformLocation</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">program</span><span class="p">,</span> <span class="s2">&quot;lightDir&quot;</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">uniform1i</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">getUniformLocation</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">program</span><span class="p">,</span> <span class="s2">&quot;sampler2d&quot;</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>

        <span class="c1">// Enable texturing</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">enable</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">TEXTURE_2D</span><span class="p">);</span>

        <span class="c1">// Create a box. On return &#39;gl&#39; contains a &#39;box&#39; property with the </span>
        <span class="c1">// BufferObjects containing the arrays for vertices, normals, texture </span>
        <span class="c1">// coords, and indices.</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span> <span class="o">=</span> <span class="nx">makeBox</span><span class="p">(</span><span class="nx">gl</span><span class="p">);</span>

        <span class="c1">// Load an image to use. Returns a CanvasTexture object</span>
        <span class="nx">spiritTexture</span> <span class="o">=</span> <span class="nx">loadImageTexture</span><span class="p">(</span><span class="nx">gl</span><span class="p">,</span> <span class="s2">&quot;spirit.jpg&quot;</span><span class="p">);</span>

        <span class="c1">// Create some matrices to use later and save their locations in the shaders</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CanvasMatrix4</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">u_normalMatrixLoc</span> <span class="o">=</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">getUniformLocation</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">program</span><span class="p">,</span> <span class="s2">&quot;u_normalMatrix&quot;</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">normalMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CanvasMatrix4</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">u_modelViewProjMatrixLoc</span> <span class="o">=</span>
                <span class="nx">gl</span><span class="p">.</span><span class="nx">getUniformLocation</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">program</span><span class="p">,</span> <span class="s2">&quot;u_modelViewProjMatrix&quot;</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvpMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CanvasMatrix4</span><span class="p">();</span>

        <span class="c1">// Enable all the vertex arrays</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">enableVertexAttribArray</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">enableVertexAttribArray</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">enableVertexAttribArray</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>

        <span class="c1">// Setup all the vertex attributes for vertices, normals and texCoords</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">bindBuffer</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">ARRAY_BUFFER</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span><span class="p">.</span><span class="nx">vertexObject</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">vertexAttribPointer</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">FLOAT</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

        <span class="nx">gl</span><span class="p">.</span><span class="nx">bindBuffer</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">ARRAY_BUFFER</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span><span class="p">.</span><span class="nx">normalObject</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">vertexAttribPointer</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">FLOAT</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

        <span class="nx">gl</span><span class="p">.</span><span class="nx">bindBuffer</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">ARRAY_BUFFER</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span><span class="p">.</span><span class="nx">texCoordObject</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">vertexAttribPointer</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">FLOAT</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

        <span class="c1">// Bind the index array</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">bindBuffer</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">ELEMENT_ARRAY_BUFFER</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span><span class="p">.</span><span class="nx">indexObject</span><span class="p">);</span>

        <span class="k">return</span> <span class="nx">gl</span><span class="p">;</span>
    <span class="p">}</span>
</pre>
</div>
</div>
<p>
After this initialization we have the shaders loaded and attached to a GLSL <em>program</em>, which is how you define the interface to your shaders. You pass <em>uniforms</em> to a shader for values that don&#8217;t change, and <em>vertex attributes</em> for things that do, like vertices. Most of this is taken care of in the library, but you can pass additional values here, like we do with the <code>lightDir</code> and <code>sampler2d</code> uniforms. Here we also tell WebGL that we want to use the arrays the <code>makeBox()</code> function set up containing the vertices, normals and texture coordinates.
</p>
<h3>Setting Up the Viewport</h3>
<p>
Before we can render, we have to tell the canvas how to map the objects we are drawing from <em>modeling coodinates</em>, which is the coordinate space we defined the box in, to <em>viewport coordinates</em>. We do that with a <em>transformation matrix</em>. We will use a perspective projection which will make closer objects look larger than further ones, just like in the real world. Here we will use the matrix library we loaded:
</p>
<div class="hlcode">
<div class="syntax">
<pre>    <span class="kd">function</span> <span class="nx">reshape</span><span class="p">(</span><span class="nx">gl</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;example1&#39;</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">clientWidth</span> <span class="o">==</span> <span class="nx">width</span> <span class="o">&amp;&amp;</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">clientHeight</span> <span class="o">==</span> <span class="nx">height</span><span class="p">)</span>
            <span class="k">return</span><span class="p">;</span>

        <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">clientWidth</span><span class="p">;</span>
        <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">clientHeight</span><span class="p">;</span>

        <span class="c1">// Set the viewport and projection matrix for the scene</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">viewport</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">width</span><span class="p">,</span> <span class="nx">height</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">perspectiveMatrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CanvasMatrix4</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">perspectiveMatrix</span><span class="p">.</span><span class="nx">lookat</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">perspectiveMatrix</span><span class="p">.</span><span class="nx">perspective</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="nx">width</span><span class="o">/</span><span class="nx">height</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10000</span><span class="p">);</span>
    <span class="p">}</span>
</pre>
</div>
</div>
<p>
We save the <code>perspectiveMatrix</code> for use later. It transforms from <em>world coordinates</em> to viewport coordinates. We will go from modeling coordinate to world coordinates in the next step.
</p>
<h3>Drawing the Box</h3>
<p>
Now we&#8217;re all set up and we can finally draw our box. Most of the hard work is done but we still have to tell the box we want it to spin, and to do that we define a <em>model-view matrix</em>, which transforms from modeling coordinates to world coordinates. This tells the box where and at what angle we want it to appear. Then we multiply that by the perspective matrix we saved before to complete the transformation all the way from modeling coordinates to viewport coordinates. We also turn the model-view matrix into a <em>normal matrix</em> so it can be used to compute the proper lighting on the box:
</p>
<div class="hlcode">
<div class="syntax">
<pre>    <span class="kd">function</span> <span class="nx">drawPicture</span><span class="p">(</span><span class="nx">gl</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// Make sure the canvas is sized correctly.</span>
        <span class="nx">reshape</span><span class="p">(</span><span class="nx">gl</span><span class="p">);</span>

        <span class="c1">// Clear the canvas</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">clear</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">COLOR_BUFFER_BIT</span> <span class="o">|</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">DEPTH_BUFFER_BIT</span><span class="p">);</span>

        <span class="c1">// Make a model/view matrix.</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span><span class="p">.</span><span class="nx">makeIdentity</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nx">currentAngle</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>

        <span class="c1">// Construct the normal matrix from the model-view matrix and pass it in</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">normalMatrix</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">normalMatrix</span><span class="p">.</span><span class="nx">invert</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">normalMatrix</span><span class="p">.</span><span class="nx">transpose</span><span class="p">();</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">uniformMatrix4fv</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">u_normalMatrixLoc</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span>
                <span class="nx">gl</span><span class="p">.</span><span class="nx">normalMatrix</span><span class="p">.</span><span class="nx">getAsCanvasFloatArray</span><span class="p">());</span>

        <span class="c1">// Construct the model-view * projection matrix and pass it in</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvpMatrix</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">mvMatrix</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">mvpMatrix</span><span class="p">.</span><span class="nx">multRight</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">perspectiveMatrix</span><span class="p">);</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">uniformMatrix4fv</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">u_modelViewProjMatrixLoc</span><span class="p">,</span> <span class="kc">false</span><span class="p">,</span>
                <span class="nx">gl</span><span class="p">.</span><span class="nx">mvpMatrix</span><span class="p">.</span><span class="nx">getAsCanvasFloatArray</span><span class="p">());</span>

        <span class="c1">// Bind the texture to use</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">bindTexture</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">TEXTURE_2D</span><span class="p">,</span> <span class="nx">spiritTexture</span><span class="p">);</span>

        <span class="c1">// Draw the cube</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">drawElements</span><span class="p">(</span><span class="nx">gl</span><span class="p">.</span><span class="nx">TRIANGLES</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">box</span><span class="p">.</span><span class="nx">numIndices</span><span class="p">,</span> <span class="nx">gl</span><span class="p">.</span><span class="nx">UNSIGNED_BYTE</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

        <span class="c1">// Finish up.</span>
        <span class="nx">gl</span><span class="p">.</span><span class="nx">flush</span><span class="p">();</span>

        <span class="c1">// Show the framerate</span>
        <span class="nx">framerate</span><span class="p">.</span><span class="nx">snapshot</span><span class="p">();</span>

        <span class="nx">currentAngle</span> <span class="o">+=</span> <span class="nx">incAngle</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">currentAngle</span> <span class="o">&gt;</span> <span class="mi">360</span><span class="p">)</span>
            <span class="nx">currentAngle</span> <span class="o">-=</span> <span class="mi">360</span><span class="p">;</span>
    <span class="p">}</span>
</pre>
</div>
</div>
<p>
Once this is all done you simply add a JavaScript timer to keep changing the angle and rendering the box in its new position and you have a spinning box!
</p>
<h3>Where to Next?</h3>
<p>
So, as you can see there&#8217;s a lot to learn about 3D rendering. There are some nice tutorials at the <a href="http://www.opengl.org/sdk/docs/tutorials/">OpenGL Site</a>. Most of these are not specific to OpenGL ES 2.0, so you&#8217;ll have to figure out what features are and are not available. Unfortunately there aren&#8217;t a lot of specific ES 2.0 examples yet. But I think these tutorials will give you a good start. There&#8217;s also a great book specifically about OpenGL ES 2.0 called the <a href="http://opengles-book.com/">OpenGL ES 2.0 Programming Guide</a>.
</p>
<p>
There are also a few WebGL examples in the wild already. Check them out <a href="http://wakaba.c3.cx/w/puls.html">here</a>, <a href="http://wakaba.c3.cx/w/escher_droste.html">here</a> and <a href="http://3bb.cc/projects/webgl/test1/">here</a>. WebKit has a few samples as well:
</p>
<table>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/SpinningBox.html">Spinning Box</a>
        </td>
<td>
            <a href="/blog-files/webgl/SpinningBox.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/SpinningBoxThumb.jpg"/><br />
            </a>
        </td>
</tr>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/Earth.html">Earth</a>
        </td>
<td>
            <a href="/blog-files/webgl/Earth.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/EarthThumb.jpg"/><br />
            </a>
        </td>
</tr>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/ManyPlanetsDeep.html">Many Planets</a>
        </td>
<td>
            <a href="/blog-files/webgl/ManyPlanetsDeep.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/ManyPlanetsDeepThumb.jpg"/><br />
            </a>
        </td>
</tr>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/TeapotPerVertex.html">Teapot per-vertex</a>
        </td>
<td>
            <a href="/blog-files/webgl/TeapotPerVertex.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/TeapotPerVertexThumb.jpg"/><br />
            </a>
        </td>
</tr>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/TeapotPerPixel.html">Teapot per-pixel</a>
        </td>
<td>
            <a href="/blog-files/webgl/TeapotPerPixel.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/TeapotPerPixelThumb.jpg"/><br />
            </a>
        </td>
</tr>
<tr>
<td style="font-size:1.5em">
            <a href="/blog-files/webgl/WebGL+CSS.html">WebGL+CSS Animation</a>
        </td>
<td>
            <a href="/blog-files/webgl/WebGL+CSS.html"><br />
            <img style="float:right" src="/blog-files/webgl/resources/WebGL+CSSThumb.jpg"/><br />
            </a>
        </td>
</tr>
</table>
</div>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/603/webgl-now-available-in-webkit-nightlies/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Pavel Feldman and Dmitry Titov are now WebKit reviewers.</title>
		<link>http://webkit.org/blog/793/pavel-feldman-and-dmitry-titov-are-now-webkit-reviewers/</link>
		<comments>http://webkit.org/blog/793/pavel-feldman-and-dmitry-titov-are-now-webkit-reviewers/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 21:51:22 +0000</pubDate>
		<dc:creator>David Levin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reviewers]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=793</guid>
		<description><![CDATA[Pavel has contributed some great new features for the Web Inspector and spent a lot of time on the Web Inspector to help unfork the Chromium port.  Dmitry has worked on timers, workers, test improvements, and various other enhancements.
Please join me in congratulating Pavel and Dmitry on their reviewer status!
]]></description>
			<content:encoded><![CDATA[<p>Pavel has contributed some great new features for the Web Inspector and spent a lot of time on the Web Inspector to help unfork the Chromium port.  Dmitry has worked on timers, workers, test improvements, and various other enhancements.</p>
<p>Please join me in congratulating Pavel and Dmitry on their reviewer status!</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/793/pavel-feldman-and-dmitry-titov-are-now-webkit-reviewers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>WebKit Page Cache II &#8211; The unload Event</title>
		<link>http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/</link>
		<comments>http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 23:29:33 +0000</pubDate>
		<dc:creator>Brady Eidson</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=516</guid>
		<description><![CDATA[Previously I touched on what exactly the Page Cache does and outlined some of the improvements we&#8217;re working on.
This post is geared towards web developers and is therefore even more technical than the last.
In this article I&#8217;d like to talk more about unload event handlers, why they prevent pages from going into the Page Cache, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://webkit.org/blog/427/webkit-page-cache-i-the-basics/">Previously</a> I touched on what exactly the Page Cache does and outlined some of the improvements we&#8217;re working on.</p>
<p>This post is geared towards web developers and is therefore even more technical than the last.</p>
<p>In this article I&#8217;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.</p>
<h3>Load/Unload Event Handlers</h3>
<p>Web developers can make use of the load and unload events to do work at certain points in the lifetime of a web page.</p>
<p>The purpose of the load event is quite straightforward: To perform initial setup of a new page once it has loaded.</p>
<p>The unload event is comparatively mysterious.  Whenever the user leaves a page it is &#8220;unloaded&#8221; and scripts can do some final cleanup.</p>
<p>The mysterious part is that &#8220;leaving the page&#8221; can mean one of a few things:</p>
<ol>
<li>The user closes the browser tab or window, resulting in the destruction of the visible page.</li>
<li>The browser navigates from the old page to a new page, resulting in the destruction of the old visible page.</li>
</ol>
<p>The Page Cache makes this even more interesting by adding a new navigation possibility:</p>
<ol start="3">
<li>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.</li>
</ol>
<h3>The Status Quo</h3>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>If we don&#8217;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.</p>
<p>If we don&#8217;t fire the unload event when going into the Page Cache but consider firing it whenever the suspended page is eventually destroyed, then we&#8217;re considering the possibility of doing something that&#8217;s never been done before: Executing scripts that belong to an invisible web page that has had its &#8220;pause&#8221; button pressed.</p>
<p>There&#8217;s all sorts of obstacles in making this work well including technological hurdles, security concerns, and user-experience considerations.</p>
<p>Since there is no clear solution for handling such pages the major browsers vendors have all come to the same conclusion: Don&#8217;t cache these pages.</p>
<h3>How You Can Help</h3>
<p>Web developers have a few things they can do to help their pages be cacheable.</p>
<p>One is to only install the unload event handler if the code is relevant to the current browser.  For example, we&#8217;ve seen unload handlers similar to the following:</p>
<pre>
    function unloadHandler()
    {
        if (_scriptSettings.browser.isIE) {
            // Run some unload code for Internet Explorer
            ...
        }
    }
</pre>
<p>In all browsers other than Internet Explorer this code does nothing, but its mere existence potentially slows down their user experience.  This developer should&#8217;ve done the browser check *before* installing the unload handler.</p>
<p>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.</p>
<p>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&#8217;t make any further changes, the unload handler should be removed.</p>
<p>Particularly savvy developers might consider a third option.</p>
<h3>A Replacement For Unload</h3>
<p>Some time ago Mozilla approached this problem differently by inventing a replacement for load/unload events.</p>
<p>The load and unload events are meant to be fired exactly once, and this is the underlying cause of the problem.  The <a href="https://developer.mozilla.org/En/Using_Firefox_1.5_caching#New_browser_events">pageshow/pagehide</a> events &#8211; which we&#8217;ve implemented in WebKit as of <a href="http://trac.webkit.org/changeset/47824">revision 47824</a> &#8211; address this.</p>
<p>Despite their name the pageshow/pagehide events don&#8217;t have anything to do with whether or not the page is actually visible on the screen.  They won&#8217;t fire when you minimize the window or switch tabs, for example.</p>
<p>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:</p>
<pre>
    &lt;html&gt;
    &lt;head&gt;
    &lt;script&gt;

    function pageLoaded()
    {
        alert("load event handler called.");
    }

    function pageUnloaded()
    {
        alert("unload event handler called.");
    }

    window.addEventListener("load", pageLoaded, false);
    window.addEventListener("unload", pageUnloaded, false);

    &lt;/script&gt;
    &lt;body&gt;
    &lt;a href="http://www.webkit.org/"&gt;Click for WebKit&lt;/a&gt;
    &lt;/body&gt;
    &lt;/html&gt;
</pre>
<p><a href="http://webkit.org/blog-files/load-unload-example.html" target="_blank">Click here</a> to view this example in a new window, in case you can&#8217;t guess what it does.</p>
<p>Try clicking the link to leave the page then press the back button.  Pretty straightforward.</p>
<p>The pageshow/pagehide fire when load/unload do, but also have one more trick up their sleeve.</p>
<p>Instead of firing only at the single discrete moment when a page is &#8220;loaded&#8221; the pageshow event is also fired when pages are restored from the Page Cache.</p>
<p>Similarly the pagehide event fires when the unload event fires but also when a page is suspended into the Page Cache.</p>
<p>By including an additional property on the event called &#8220;persisted&#8221; the events tell the page whether they represent the load/unload events or saving/restoring from the Page Cache.</p>
<p>Here&#8217;s the same example using pageshow/pagehide:</p>
<pre>
    &lt;html&gt;
    &lt;head&gt;
    &lt;script&gt;

    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.");
    }

    window.addEventListener("pageshow", pageShown, false);
    window.addEventListener("pagehide", pageHidden, false);

    &lt;/script&gt;
    &lt;body&gt;
    &lt;a href="http://www.webkit.org/"&gt;Click for WebKit&lt;/a&gt;
    &lt;/body&gt;
    &lt;/html&gt;
</pre>
<p><a href="http://webkit.org/blog-files/pageshow-pagehide-example.html" target="_blank">Click here</a> to view this example in a new window, but make sure you&#8217;re using a recent <a href="http://nightly.webkit.org/">WebKit nightly.</a></p>
<p>Remember to try clicking the link to leave the page then press the back button.</p>
<p>Pretty cool, right?</p>
<h3>What These New Events Accomplish</h3>
<p>The pagehide event is important for two reasons:</p>
<ol>
<li>It enables web developers to distinguish between a page being suspended and one that is being destroyed.</li>
<li>When used instead of the unload event, it enables browsers to use their page cache.</li>
</ol>
<p>It&#8217;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&#8217;re not:</p>
<pre>
    &lt;html&gt;
    &lt;head&gt;
    &lt;script&gt;

    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;
        }

        // This is either a load event for older browsers,
        // or a pageshow event for the initial load in supported browsers.
        // It's safe to do everything my old load event handler did here.
        ...
    }

    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;
        }

        // This is either an unload event for older browsers,
        // or a pagehide event for page tear-down in supported browsers.
        // It's safe to do everything my old unload event handler did here.
        ...
    }

    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);
    }

    &lt;/script&gt;
    &lt;body&gt;
    Your content goes here!
    &lt;/body&gt;
    &lt;/html&gt;
</pre>
<p>Piece of cake!</p>
<h3>How You Can Help: Revisited</h3>
<p>To reiterate, we&#8217;ve now identified three great ways web developers can help the Page Cache work better:</p>
<ol>
<li>Only install the event handler if the code is relevant to the current browser.</li>
<li>Only install the event handler once your page actually needs it.</li>
<li>If supported by the browser, use pagehide instead.</li>
</ol>
<p>Web developers that willfully ignore any or all these options are primarily accomplishing one thing:<br />
Forcing their users into &#8220;slow navigation mode.&#8221; </p>
<p>I say this both as a browser engineer and a browser user: That stinks!</p>
<h3>The Plot Thickens</h3>
<p>But now that we&#8217;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.</p>
<p>Browsers treat the unload handler as sacred because it is designed to do &#8220;important work.&#8221;  Unfortunately many popular sites have unload event handlers that decidedly <i>do not</i> &#8220;do important work.&#8221;  I commonly see handlers that:</p>
<ul>
<li>Always update some cookie for tracking, even though it&#8217;s already been updated.</li>
<li>Always send an XHR update of draft data to a server, even though it&#8217;s already been sent.</li>
<li>Do nothing that could possible persist to any future browsing session.</li>
<li>That are empty.  They literally do <i>nothing.</i></li>
</ul>
<p>Since these misbehaved pages are very common and will render improvements to WebKit&#8217;s Page Cache ineffective a few of us started to ask the question:</p>
<p>What *would* actually happen if we simply started admitting these pages to the Page Cache without running the unload event handler first?</p>
<p>What would break?  </p>
<p>Can we detect any patterns to determine whether an unload event handler is &#8220;important&#8221; or not?</p>
<h3>Our Experiment</h3>
<p>You never know for sure until you try.</p>
<p>Starting in <a href="http://trac.webkit.org/changeset/48388">revision 48388</a> we&#8217;ve allowed pages with unload handlers into the Page Cache.  If a user closes the window while the page is visible, the unload event will fire as usual.  But the unload event will not be fired as normal when the user navigates away from the page.  If the user closes the window while the page is suspended and in the Page Cache, the unload event handler will never be run.</p>
<p>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&#8217;re consciously deciding not to run some of their code and their web application might break.</p>
<p>For users and developers alike &#8211; Please leave your feedback, observations, or suggestions in <a href="http://webkit.org/b/29021">the bug</a> tracking this experiment.</p>
<p>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&#8217;re willing to push the envelope a little to improve it a lot.</p>
<p>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.</p>
<p>At least one popular Javascript library has <a href="http://www.dojotoolkit.org/book/dojo-1-3-release-notes">already adopted some of the advice</a> we&#8217;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.</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WebKit Page Cache I &#8211; The Basics</title>
		<link>http://webkit.org/blog/427/webkit-page-cache-i-the-basics/</link>
		<comments>http://webkit.org/blog/427/webkit-page-cache-i-the-basics/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 23:47:13 +0000</pubDate>
		<dc:creator>Brady Eidson</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=427</guid>
		<description><![CDATA[This is the first of two posts that will center around a modern browser engine feature that doesn&#8217;t usually get a lot of press: The Page Cache.
Today I&#8217;ll talk a bit about what this feature is, why it often doesn&#8217;t work, and what plans we have to improve it.
Page Cache Overview
Some of you might be [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first of two posts that will center around a modern browser engine feature that doesn&#8217;t usually get a lot of press: The Page Cache.</p>
<p>Today I&#8217;ll talk a bit about what this feature is, why it often doesn&#8217;t work, and what plans we have to improve it.</p>
<h3>Page Cache Overview</h3>
<p>Some of you might be more familiar with what other browsers call their Page Cache.  Firefox calls theirs the &#8220;Back-Forward Cache&#8221; or &#8220;bfcache.&#8221;  Opera refers to theirs as &#8220;Fast History Navigation.&#8221;  We&#8217;ve recently started to refer to WebKit&#8217;s implementation as the &#8220;Page Cache&#8221; to reduce confusion with our &#8220;Back/Forward List.&#8221;</p>
<p>Note that the Page Cache is an end user feature that makes navigating the web much smoother.  It is not a &#8220;cache&#8221; in the &#8220;<a href="http://www.ietf.org/rfc/rfc2616.txt">HTTP sense</a>&#8220;.  It is not a &#8220;cache&#8221; in the &#8220;disk cache&#8221; sense where raw resources are stored on the local disk.  And it&#8217;s not a &#8220;cache&#8221; in the traditional &#8220;memory cache&#8221; sense where WebKit keeps decoded resources around in memory to be shared between multiple web pages.</p>
<p>So&#8230; what *exactly* is it?</p>
<p>Quite simply, the Page Cache makes it so when you leave a page we &#8220;pause&#8221; it and when you come back we press &#8220;play.&#8221;</p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<h3>Why is This Important?</h3>
<p>When the Page Cache works it makes clicking the back button almost instantaneous.</p>
<p>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 &#8220;back&#8221; and &#8220;forward&#8221; rapidly.  Or you might have simply clicked on the wrong link and want to go back to correct your mistake.</p>
<p>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&#8217;re not aware of the magic behind the scenes.</p>
<p>Conversely, when the Page Cache is bypassed, users often get frustrated with both the browser and the Web in general.  </p>
<h3>Why Wouldn&#8217;t it Work?</h3>
<p>So if the Page Cache is so amazing, why doesn&#8217;t WebKit always use it when you navigate to a new page?</p>
<p>There&#8217;s a few main answers to that question.</p>
<h4>Some Pages aren&#8217;t Interesting</h4>
<p>First off, sometimes it doesn&#8217;t make sense to cache a page because it&#8217;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&#8217;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.</p>
<p>These are cases where we&#8217;re happy with the current Page Cache behavior in WebKit.</p>
<h4>Some Pages are Complicated</h4>
<p>Secondly, a page might not be considered for the Page Cache because it&#8217;s difficult to figure out how to &#8220;pause&#8221; it.  This happens with more complex pages that do interesting things.  </p>
<p>For example, plug-ins contain native code that can do just about anything it wants so WebKit can&#8217;t &#8220;hit the pause button&#8221; on them.  Another example is pages with multiple frames which WebKit has historically not cached.  </p>
<p>Distressingly, navigating around these more advanced pages would benefit the most from the Page Cache. </p>
<h4>Some Pages are Secure</h4>
<p>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&#8217;s behavior before allowing it to be used by their customers.  </p>
<p>One area often focused on is back/forward behavior.  Such institutions are &#8211; understandably &#8211; 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.  </p>
<p>A more fine grained approach might go a long way towards improving the user experience.</p>
<h3>Planned Improvements</h3>
<p>Clearly there&#8217;s some important cases we don&#8217;t handle and therefore plenty of room for improvement.</p>
<p>WebKit&#8217;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.  </p>
<p>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.</p>
<p>For example, as of <a href="http://trac.webkit.org/changeset/48036">revision 48036</a> a major limitation was resolved and pages with frames are now placed in the Page Cache.  Browsing with the <a href="http://nightly.webkit.org/">latest WebKit nightly</a> always seems to &#8220;feel faster&#8221; in ways you can&#8217;t quite put your finger on, and recently some of you might have been experiencing this enhancement.</p>
<p>But there&#8217;s plenty more work to do.</p>
<p>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&#8217;t reliably hit the &#8220;pause&#8221; button on them.  </p>
<p>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.</p>
<p><a href="http://webkit.org/b/13634">Bug #13634</a> tracks getting this working again for all plug-ins on all pages.</p>
<p>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.  </p>
<p><a href="http://webkit.org/b/26777">Bug #26777</a> tracks allowing HTTPS pages to be cached unless their response headers include &#8220;cache-control: no-store&#8221; or &#8220;cache-control: no-cache&#8221; which has become the canonical way for a selective organization to secure your content.</p>
<p>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!</p>
<h3>Unload Handlers</h3>
<p>One thing I haven&#8217;t mentioned is pages with unload event handlers.  </p>
<p>The unload event was designed to let a page do some cleanup work when the user closes the page.  </p>
<p>The browser can&#8217;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.  </p>
<p>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 &#8220;paused&#8221; and hidden, and that cleanup work &#8211; which might be very important &#8211; will never happen.</p>
<p>Since the unload event&#8217;s purpose is to allow &#8220;important work when a page is closed,&#8221; all major browsers refuse to put such pages in their Page Cache, causing a direct negative impact on the user experience.</p>
<p>In a future post I&#8217;ll be talking more about unload event handlers and there will actually be homework for many of you web developers out there!  Stay tuned&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/427/webkit-page-cache-i-the-basics/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Eric Carlson is now a WebKit Reviewer</title>
		<link>http://webkit.org/blog/426/eric-carlson-is-now-a-webkit-reviewer/</link>
		<comments>http://webkit.org/blog/426/eric-carlson-is-now-a-webkit-reviewer/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 10:34:30 +0000</pubDate>
		<dc:creator>Eric Seidel</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reviewers]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/426/eric-carlson-is-now-a-webkit-reviewer/</guid>
		<description><![CDATA[Eric Carlson has been a long-time contributer to WebKit, first through the QuickTime Plugin, and now directly as part of WebKit&#8217;s HTML5 media support.  Eric knows a ridiculous amount about video and audio and we&#8217;re very glad to have him now as an official reviewer!  Please join me in welcoming Eric as a [...]]]></description>
			<content:encoded><![CDATA[<p>Eric Carlson has been a long-time contributer to WebKit, first through the QuickTime Plugin, and now directly as part of WebKit&#8217;s HTML5 media support.  Eric knows a ridiculous amount about video and audio and we&#8217;re very glad to have him now as an official reviewer!  Please join me in welcoming Eric as a reviewer.</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/426/eric-carlson-is-now-a-webkit-reviewer/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>3D Transforms</title>
		<link>http://webkit.org/blog/386/3d-transforms/</link>
		<comments>http://webkit.org/blog/386/3d-transforms/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 19:02:29 +0000</pubDate>
		<dc:creator>Simon Fraser</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=386</guid>
		<description><![CDATA[WebKit on Mac OS X now has support for CSS 3D transforms, which allow you to position elements on the page in three-dimensional space using CSS. This is a natural extension of 2D transforms, which we described in an earlier blog post. 3D transforms have been supported on iPhone since 2.0, and now we&#8217;re please [...]]]></description>
			<content:encoded><![CDATA[<p>WebKit on Mac OS X now has support for <a href="http://www.w3.org/TR/css3-3d-transforms/"title="CSS 3D Transforms Module Level 3">CSS 3D transforms</a>, which allow you to position elements on the page in three-dimensional space using CSS. This is a natural extension of 2D transforms, which we described in an earlier <a href="http://webkit.org/blog/130/css-transforms/" title="Surfin&#8217; Safari - Blog Archive  &raquo; CSS Transforms">blog post</a>. 3D transforms have been supported on iPhone since 2.0, and now we&#8217;re please to announce that we have currently added support for Leopard and later.</p>
<p>If you want to jump right in and see a demo, make sure you&#8217;re running <a href="http://nightly.webkit.org/" title="WebKit Nightly Builds">recent WebKit nightly build</a> on Leopard or later, and load this example:</p>
<p><a href="/blog-files/3d-transforms/poster-circle.html">Poster Circle</a></p>
<p>Here&#8217;s a screenshot for those not running a recent-enough WebKit (if you are, hover over it for a treat!):</p>
<p><iframe src="/blog-files/3d-transforms/image-flip.html" scrolling="no" style="display: block; border: none; margin: 0 auto; height: 300px; width: 280px;"></iframe></p>
<p>Like many of the examples you&#8217;ll see here, this one combines CSS transforms with <a href="http://webkit.org/blog/138/css-animation/" title="Surfin&#8217; Safari - Blog Archive  &raquo; CSS Animation">CSS transitions and animations</a> to great effect.</p>
<p>3D transforms are applied via the same <code>-webkit-transform</code> property as 2D transforms. For example, here&#8217;s how to rotate an element about the Y (vertical) axis:</p>
<pre>
-webkit-transform: rotateY(45deg);
</pre>
<p>There are several new transform functions available for use in the <code>-webkit-transform</code> property:</p>
<dl>
<dt>translate3d(x, y, z), translateZ(z)</dt>
<dd>Move the element in x, y and z, and just move the element in z. Positive z is towards the viewer. Unlike x and y, the z value cannot be a percentage.</dd>
<dt>scale3d(sx, sy, sz), scaleZ(sz)</dt>
<dd>Scale the element in x, y and z. The z scale affects the scaling along the z axis in transformed children.</dd>
<dt>rotateX(angle), rotateY(angle), rotate3d(x, y, z, angle), </dt>
<dd>The first two forms simply rotate the element about the horizontal and vertical axes. Angle units can be degrees (deg) radians (rad) or gradians (grad). The last form allows you to rotate the element around an arbitrary vector in 3D space; x, y and z should specify the unit vector you wish to rotate around (we&#8217;ll normalize it for you).</dd>
<dt>perspective(p)</dt>
<dd>This function allows you to put some perspective into the transformation matrix. For an explanation of <em>p</em>, see below. Normally perspective is applied via the <code>-webkit-perspective</code> property, but this function allows you to get a perspective effect for a single element, with something like:</p>
<pre>
-webkit-transform: perspective(500px) rotateY(20deg);
</pre>
</dd>
<dt>matrix3d(&#8230;)</dt>
<dd>This function allows you to specify the raw 4&#215;4 homogeneous transformation matrix of 16 values in column-major order. Have fun with that!</dd>
</dl>
<p>We&#8217;ve also extended one other CSS transform property, and implemented the four other 3D-related properties described in the spec:
</p>
<p><strong><code>-webkit-transform-origin</code></strong> now accepts three values, allowing you to specify a z offset for the transform origin.</p>
<p><strong><code>-webkit-perspective</code></strong> is used to give an illusion of depth; it determines how things change size based on their z-offset from the z=0 plane. You can think of it as though you&#8217;re looking at the page from a distance <em>p</em> away. Objects on the z=0 plane appear in their normal size. Something at a z offset of <em>p</em>/2 (halfway between the viewer and the z=0 plane) will look twice as big, and something at a z offset of -<em>p</em> will look half as big. Thus, large values give a little foreshortening effect, and small values lots of foreshortening. Values between 500px and 1000px give a reasonable-looking result for most content. </p>
<p>The default origin for the perspective effect is the center of the element&#8217;s border box, but you can control this with <strong><code>-webkit-perspective-origin</code></strong>. </p>
<p>
Here&#8217;s an example that shows how perspective works:
</p>
<p><a href="/blog-files/3d-transforms/perspective-by-example.html">Perspective</a></p>
<p> The interesting thing about <code>-webkit-perspective</code> is that it does not affect the element directly. Instead, it affects the appearance of the 3D transforms on the transformed <em>descendants</em> of that element; you can think of it as adding a transform that gets multiplied into the descendant transforms. This allows those descendants to all share the same perspective as they move around. </p>
<p>We&#8217;ve described how you can assign 3D transforms to elements and make them look three-dimensional with some perspective. However, so far, all the effects are really just painting effects. Those transformed children are still rendering into the plane of their parent; in other words, they are <em>flattened</em>. </p>
<p>When you start to build hierarchies of objects with 3D transforms, flattening is not what you want. You want parents and children to live in a shared three-dimensional space, and to all share the same perspective which propagates up from some container. This is where <code>-webkit-transform-style</code> comes in. </p>
<p><strong><code>-webkit-transform-style</code></strong> has two values:</p>
<ul>
<li><code>flat</code>: This is the default value, and gives the behavior described above; transformed children are flattened into the plane of their parent (think of the 3D transform as simply a painting effect).</li>
<li><code>preserves-3d</code>: This value states that the element to which it is assigned does not flatten its children into it; instead, those children live in a shared 3D space with the element.</li>
</ul>
<p>Here&#8217;s an example that shows transform-style in action:</p>
<p><a href="/blog-files/3d-transforms/transform-style.html">Transform Style</a></p>
<p>A common pattern, therefore, is to have content that looks like this:</p>
<pre>
&lt;div class="container" style="-webkit-perspective: 600px"&gt;
  &lt;div class="box" style="-webkit-transform-style: preserve-3d; -webkit-transform: rotateY(10deg)"&gt;
    &lt;div class="leaf" style="-webkit-transform: rotateX(10deg)"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</pre>
<p>Here both &#8216;leaf&#8217; and &#8216;box&#8217; share the same 3D space, so both appear with the perspective specified on the container. &#8216;box&#8217; can also be rotated with a transition or animation, and &#8216;leaf&#8217; will move around as &#8216;box&#8217; moves, in perspective.</p>
<p>One thing you may have noticed in these demos is that it&#8217;s quite common to have a 3D transform that flips an element around so that you can see its reverse side. In some cases you don&#8217;t want the element to appear at all in this situation (say, for example, you want to position two elements back-to-back, so you need to hide the one that&#8217;s facing away from the viewer). This is the reason for the last 3d-related property, <strong><code>-webkit-backface-visibility</code></strong>. Its two values&mdash;<code>visible</code> (the default), and <code>hidden</code>&mdash;specify whether the element is visible or not when that element is transformed such that its back face is towards the viewer. </p>
<p>Here&#8217;s a final example that shows backface-visibility in action, along with more 3D goodness, animations and transitions:</p>
<p><a href="/blog-files/3d-transforms/morphing-cubes.html">Morphing Power Cubes</a></p>
<p><img style="display: block; margin: 0 auto;" src="/blog-files/3d-transforms/mighty-cubes.png" width="415" height="175" alt="Mighty Cubes"/></p>
<p> For more information, see the CSS working drafts on <a href="http://www.w3.org/TR/css3-2d-transforms/" title="CSS 2D Transforms Module Level 3">2D transforms</a>, <a href="http://www.w3.org/TR/css3-3d-transforms/" title="CSS 3D Transforms Module Level 3">3D transforms</a>, <a href="http://www.w3.org/TR/css3-transitions/" title="CSS Transitions Module Level 3">transitions</a> and <a href="http://www.w3.org/TR/css3-animations/" title="CSS Animations Module Level 3">animations</a>. There is also documentation in the <a href="http://developer.apple.com/safari/library/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Transforms/Transforms.html" title="Safari Visual Effects Guide: Transforms">Safari Reference Library</a>.</p>
<p>We hope you have a blast with these new features, and share your creations with us. If you find bugs, please report them at <a href="http://bugs.webkit.org/">bugs.webkit.org</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/386/3d-transforms/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Adam Barth and Dave Levin are now WebKit reviewers</title>
		<link>http://webkit.org/blog/379/adam-barth-and-dave-levin-are-now-webkit-reviewers/</link>
		<comments>http://webkit.org/blog/379/adam-barth-and-dave-levin-are-now-webkit-reviewers/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 22:13:26 +0000</pubDate>
		<dc:creator>Eric Seidel</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reviewers]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=379</guid>
		<description><![CDATA[Adam has been a long-time contributer of security fixes.   Dave comes to us through the Chromium porting effort and has done quite a bit of work on HTML5 Workers as well.  Please join me in congratulating Adam and Dave on their reviewer status!
]]></description>
			<content:encoded><![CDATA[<p>Adam has been a long-time contributer of security fixes.   Dave comes to us through the Chromium porting effort and has done quite a bit of work on HTML5 Workers as well.  Please join me in congratulating Adam and Dave on their reviewer status!</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/379/adam-barth-and-dave-levin-are-now-webkit-reviewers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Jan Michael Alonzo is now a WebKit Reviewer</title>
		<link>http://webkit.org/blog/377/jan-michael-alonzo-is-now-a-webkit-reviewer/</link>
		<comments>http://webkit.org/blog/377/jan-michael-alonzo-is-now-a-webkit-reviewer/#comments</comments>
		<pubDate>Wed, 13 May 2009 19:46:36 +0000</pubDate>
		<dc:creator>Gustavo Noronha</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reviewers]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=377</guid>
		<description><![CDATA[Jan has been around for a very long time now, and has contributed lots of patches to the GTK+ port of WebKit. He&#8217;s worked tirelessly on the build system, and on keeping the port compilable. He has also done important work on the testing infra-structure, and contributed sizable chunks of API. Please join me in congratulating [...]]]></description>
			<content:encoded><![CDATA[<p>Jan has been around for a very long time now, and has contributed lots of patches to the GTK+ port of WebKit. He&#8217;s worked tirelessly on the build system, and on keeping the port compilable. He has also done important work on the testing infra-structure, and contributed sizable chunks of API. Please join me in congratulating Jan on his reviewer status!</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/377/jan-michael-alonzo-is-now-a-webkit-reviewer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Xan Lopez and Gustavo Noronha are now WebKit reviewers</title>
		<link>http://webkit.org/blog/375/xan-lopez-and-gustavo-noronha-are-now-webkit-reviewers/</link>
		<comments>http://webkit.org/blog/375/xan-lopez-and-gustavo-noronha-are-now-webkit-reviewers/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 22:10:55 +0000</pubDate>
		<dc:creator>Mark Rowe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[reviewers]]></category>

		<guid isPermaLink="false">http://webkit.org/blog/?p=375</guid>
		<description><![CDATA[Over the last six months, Xan Lopez and Gustavo Noronha have been working tirelessly on the GTK+ port of WebKit.  They&#8217;ve contributed over 150 improvements to WebKit in the form of bug fixes and API improvements, and have played important roles in driving the development of the GTK+ port forward and assisting contributors that [...]]]></description>
			<content:encoded><![CDATA[<p>Over the last six months, Xan Lopez and Gustavo Noronha have been working tirelessly on the GTK+ port of WebKit.  They&#8217;ve contributed over 150 improvements to WebKit in the form of bug fixes and API improvements, and have played important roles in driving the development of the GTK+ port forward and assisting contributors that are new to the WebKit project.  Please join me in congratulating Xan and Gustavo on their reviewer status!</p>
]]></content:encoded>
			<wfw:commentRss>http://webkit.org/blog/375/xan-lopez-and-gustavo-noronha-are-now-webkit-reviewers/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
