<?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>An Experiment in Bloggery</title>
	<atom:link href="http://kevin.sb.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://kevin.sb.org</link>
	<description>The occasional view into my life</description>
	<lastBuildDate>Fri, 10 May 2013 20:12:40 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>TinEye Safari Extensions</title>
		<link>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/</link>
		<comments>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 05:43:14 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[tineye]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=242</guid>
		<description><![CDATA[TinEye is a cool reverse image search engine. It lets you take an image and search for it on the web, even finding uncropped, expanded, or unwatermarked versions of the image. Sadly, while TinEye provides plugins for both Firefox and Chrome, they don&#8217;t provide one for Safari. Because of this, I have written my own [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.tineye.com">TinEye</a> is a cool reverse image search engine. It lets you take an image and search for it on the web, even finding uncropped, expanded, or unwatermarked versions of the image. Sadly, while TinEye provides plugins for both Firefox and Chrome, they don&#8217;t provide one for Safari. Because of this, I have written my own extension. Just install it, then right-click on any image and you should see &#8220;Search Image on TinEye&#8221;. You can <a href="http://github.com/kballard/TinEye-for-Safari">get it here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CleanGoogle Safari extension</title>
		<link>http://kevin.sb.org/2010/06/10/cleangoogle-safari-extension/</link>
		<comments>http://kevin.sb.org/2010/06/10/cleangoogle-safari-extension/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 07:43:09 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[safari]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=226</guid>
		<description><![CDATA[If you&#8217;re like anybody else that I know, you were rather shocked and appalled to see Google follow the likes of Bing and add background images to their home page. If you&#8217;re also like anybody else that I know, you&#8217;re aware that Safari 5 was released with support for extensions. And if you&#8217;re like me, [...]]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;re like anybody else that I know, you were rather shocked and appalled to see Google follow the likes of <a href="bing.com">Bing</a> and add background images to their home page. If you&#8217;re also like anybody else that I know, you&#8217;re aware that Safari 5 was released with support for extensions. And if you&#8217;re like me, you thought that the new extensions behavior might be a great way to, erm, &#8220;fix&#8221; Google. Inspired by a tweet from <a href="http://twitter.com/rentzsch/status/15831330366">@rentzsch</a>, I decided to figure out how this might be done. I am, of course, not a JavaScript programmer, and Google&#8217;s front page code is quite obfuscated, but after playing around with it for a bit over an hour, I got something that worked. Unfortunately it also has the side-effect of blocking the fairly nice fade-in of all the text content, and it&#8217;s also a bit fragile, but if you absolutely cannot stand the background image, feel free to <a href="/files/CleanGoogle.safariextz">download the extension</a> and try it out.</p>

<p><strong>Update</strong>: I played around for a few more hours and got something much better. It&#8217;s still fragile, but not nearly so much as before, and it restores the fade effect for all the google content. Same <a href="/files/CleanGoogle.safariextz">download link</a> as before.</p>

<p><strong>Update 2</strong>: Looks like Google fixed their homepage sometime this morning, so this extension is now officially obsolete. I will continue to host the download if anybody is interested in the code.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2010/06/10/cleangoogle-safari-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>1Password extension loading in Snow Leopard</title>
		<link>http://kevin.sb.org/2009/09/02/1password-extension-loading-in-snow-leopard/</link>
		<comments>http://kevin.sb.org/2009/09/02/1password-extension-loading-in-snow-leopard/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 22:11:11 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[1Password]]></category>
		<category><![CDATA[64bit]]></category>
		<category><![CDATA[osax]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[Snow Leopard]]></category>
		<category><![CDATA[WebKit]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=201</guid>
		<description><![CDATA[One of the big changes in Snow Leopard is the move to 64-bit applications system-wide. This includes Safari. Unfortunately, this change breaks all of the Safari plugins out there, including mine. There&#8217;s two reasons for this. The first is simply that these plugins are all 32-bit binaries, and a 64-bit app cannot load a 32-bit [...]]]></description>
				<content:encoded><![CDATA[<p>One of the big changes in Snow Leopard is the move to 64-bit applications system-wide. This includes Safari. Unfortunately, this change breaks all of the Safari plugins out there, including mine. There&#8217;s two reasons for this. The first is simply that these plugins are all 32-bit binaries, and a 64-bit app cannot load a 32-bit binary. The second, and significantly harder obstacle, is that the entire Input Manager mechanism has been eliminated in 64-bit apps.</p>

<p>Read more to find out how 1Password gets around these limitations.</p>

<p><span id="more-201"></span></p>

<h4>A bit of history</h4>

<p>When Cocoa was introduced, one of the behaviors that every Cocoa application automatically acquired was the loading of Input Managers. These Input Managers were intended to allow developers to extend the text input system of OS X in ways that the system did not provide by default. However, these Input Managers were really nothing more than Cocoa bundles that got loaded by every single Cocoa app at launch. This means that it was very quickly abused to become a general plugin mechanism for applications that do not natively support plugins (such as Safari). In recent OS updates, Apple has been deprecating this mechanism, and now in Snow Leopard it&#8217;s completely gone for 64-bit apps.</p>

<h4>How can I use Safari plugins?</h4>

<p>The simplest way is to simply right-click Safari in the Finder, select Get Info, and check the Open in 32-bit mode checkbox. However, this has the downside of removing all of the performance benefits of 64-bit apps. Besides the normal benefits of an improved instruction set and a more modern Objective-C runtime, Safari&#8217;s JavaScript engine particularly benefits from running in 64-bit mode. So while this is a stopgap measure, it isn&#8217;t suitable for long-term use.</p>

<p>Luckily, the smart folks who make <a href="http://agilewebsolutions.com/products/1Password" title="Agile Web Solutions">1Password</a> came up with a solution for their upcoming 1Password 3.0 (which is in public beta right now). I have only done some minimal poking around, but I believe I&#8217;ve figured out the mechanism they use to load their plugin into Safari in the absence of Input Managers.</p>

<h4>Sow how does it work already?</h4>

<p>First, an introduction to <a href="http://en.wikipedia.org/wiki/AppleScript">AppleScript</a> and <a href="http://developer.apple.com/mac/library/technotes/tn/tn1164.html">Scripting Additions</a>. AppleScript is a rather old technology, first introduced in <a href="http://en.wikipedia.org/wiki/System_7" title="Mac OS 7">System 7</a>. It is a human-readable scripting language that can control any application that implements support for it, along with a slew of system functions and, more recently, generic control of UI elements[^1]. Under the hood, it sends <a href="http://en.wikipedia.org/wiki/Apple_events">Apple events</a> to actually talk to each process. Scripting additions are bundles that provide additional functionality to AppleScript, generally by installing Apple event handlers or doing Apple event data coercion. Several scripting additions are bundled with the system, such as the Keychain Scripting addition which provides access to the Keychain from within AppleScripts.</p>

<h4>What does this have to do with 1Password?</h4>

<p>I&#8217;m getting there. The thing about scripting additions is that they will be potentially loaded by any process on the system. Generally, they get loaded into a process that attempts to use an AppleEvent that the scripting addition handles. Here it gets a little fuzzy, as the documentation does not specify whether the sending process or the receiving process loads the scripting addition. In general, it doesn&#8217;t matter, and so I suspect the sending process is usually the one that handles the event[^2]. In fact, up through Mac OS X 10.5, the &#8220;context&#8221; for a scripting addition was always assumed to be &#8220;Machine&#8221;, which means the AppleEvent can be handled by any process on the machine it was sent to[^3]. New in 10.6 is the ability to specify exactly which context the scripting addition handler must execute in, including &#8220;Any&#8221;, &#8220;Machine&#8221;, &#8220;User&#8221;, or &#8220;Process&#8221;. That last context is the important one, as it means the scripting addition handler must be executed in the Apple event&#8217;s target process.</p>

<p>There is one caveat here which is that if a process has not initialized AppleScript, it will not have loaded any scripting additions. You can get around this by sending the kASAppleScriptSuite/kGetAEUT (ascr/gdut) Apple event to a process (according to <a href="http://developer.apple.com/mac/library/qa/qa2001/qa1070.html" title="Technical Q&#038;A QA1070">QA1070</a> the system automatically installs the handler for kASAppleScriptSuite/kGetAEUT on Mac OS X 10.2 or later). This event causes the &#8220;system handler table&#8221; for that process to be initialized, which loads the scripting additions.</p>

<h4>So we can load Scripting Additions. What now?</h4>

<p>The ability to load a scripting addition into a target process simply by sending it an Apple event is the key mechanism that allows us to restore the old Input Manager functionality. And this is exactly what 1Password does. 1Password includes a scripting addition that handles the ONEP/Load Apple event with a context of &#8220;Process&#8221;. This handler takes a single argument, the path to a given bundle, and it loads that specified bundle into the target process. The last component is a background daemon called 1PasswordAgent. This daemon sends the ONEP/Load Apple event to Safari immediately after Safari is launched[^4], causing Safari to load the 1Password WebKit plugin. You can see this in the following AppleEvent log:</p>

<p>~~~
{ 1 } &#8216;aevt&#8217;:  ONEP/Load (i386){
          return id: 284 (0x11c)
     transaction id: 0 (0x0)
  interaction level: 64 (0x40)
     reply required: 0 (0x0)
             remote: 0 (0x0)
      for recording: 0 (0x0)
         reply port: 37635 (0x9303)
  target:
    { 1 } &#8216;psn &#8216;:  8 bytes {
      { 0x0, 0x1a01a } (1PasswordAgent)
    }
  fEventSourcePSN: { 0x0,0x1a01a } (1PasswordAgent)
  optional attributes:
    &lt; empty record >
  event data:
    { 1 } &#8216;aevt&#8217;:  - 1 items {
      key &#8216;&#8212;&#8212;&#8217; - 
        { 1 } &#8216;TEXT&#8217;:  70 bytes {
          &#8220;/Applications/1Password.app/Contents/Extensions/WebKitExtension.bundle&#8221;
        }
    }
}
~~~</p>

<h4>Is that it?</h4>

<p>Yep, that&#8217;s it. Through the use of the Scripting Additions mechanism and a daemon, 1Password is able to load its bundle into 64-bit processes. This is actually fairly similar to how applications that use <a href="http://rentzsch.com/mach_inject/">mach_inject</a> work, except instead of injecting code at the mach level, it leverages existing higher-level interprocess communication mechanisms, which is likely to be far safer.</p>

<p>There is one more step. Safari sends an AppleEvent back to 1PasswordAgent (1Pwd/UNLK) after the bundle has been loaded. I am not sure what the purpose of this is, but I suspect UNLK stands for &#8220;Unlock&#8221; and is used for some sort of synchronization between the 1Password extension and 1PasswordAgent. It should not be necessary for most plugins.</p>

<h4>How do I use this in my own Safari plugin?</h4>

<p>At the moment, the only way is to do all the work that the 1Password guys did, and run your own daemon in the background to load your plugin into Safari. Perhaps if enough people ask, the 1Password guys will generalize their solution into something like SIMBL, e.g. a generic application plugin loader. Or maybe someone who reads this will be inspired to do it themselves.</p>

<p>One last thing: Apple clearly does not like bundles loading themselves into arbitrary processes on the system. And for a good reason. A lot of crashes and instability in the system are caused by poorly-written Input Managers or APE Haxies. This is why they removed the Input Manager system entirely. Unfortunately, as long as Safari continues to have no plugin API, such hacks are necessary to be able to use products like 1Password. If you choose to use this mechanism yourself, just be aware that Apple will most certainly frown upon it, and may try and take steps to eliminate this hole in future versions of the OS. And please, make sure your plugin is bug-free and future-compatible[^5]. The absolute worst thing you can do is cause users to experience crashes in applications.</p>

<p>[^1]: Controlling UI elements requires turning on the &#8220;Enable access for assistive devices&#8221; checkbox in the Universal Access preference pane.
[^2]: At least, on Snow Leopard. It seems Leopard always loaded the scripting addition into the target process, as it did not have the concept of a context.
[^3]: AppleEvents can be sent between machines if Remote Apple Events is enabled in the Sharing preference pane.
[^4]: As I suggested earlier, it actually sends the kASAppleScriptSuite/kGetAEUT (ascr/gdut) Apple event to Safari first, to ensure the scripting addition has been loaded.
[^5]: One of the big wins of SIMBL was that it made it so easy to specify a maximum supported bundle version for your plugin, and it strongly encouraged that you always set this to the current bundle version. In other words, whenever Safari got updated, you would be forced to test your plugin against the latest version of Safari and re-certify it as correct, or it would simply disable itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/09/02/1password-extension-loading-in-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Zynga is Hiring</title>
		<link>http://kevin.sb.org/2009/05/18/zynga-is-hiring/</link>
		<comments>http://kevin.sb.org/2009/05/18/zynga-is-hiring/#comments</comments>
		<pubDate>Mon, 18 May 2009 21:17:52 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[work]]></category>
		<category><![CDATA[hiring]]></category>
		<category><![CDATA[jobs]]></category>
		<category><![CDATA[Zynga]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=186</guid>
		<description><![CDATA[If you&#8217;ve been following me, you&#8217;re aware that I&#8217;ve been working at Zynga for the past two weeks. Well, they&#8217;re still hiring more people (and not just iPhone developers). You can see the available positions at zynga.com/jobs. If you&#8217;re interested in any of them, please contact me and I&#8217;ll send your info along to the [...]]]></description>
				<content:encoded><![CDATA[<p>If you&#8217;ve been following me, you&#8217;re aware that I&#8217;ve been working at <a href="http://www.zynga.com">Zynga</a> for the past two weeks. Well, they&#8217;re still hiring more people (and not just iPhone developers). You can see the available positions at <a href="http://www.zynga.com/jobs">zynga.com/jobs</a>. If you&#8217;re interested in any of them, please <a href="mailto:kevin@sb.org">contact me</a> and I&#8217;ll send your info along to the right person.</p>

<p><strong>Update</strong>: Every now and then people keep coming to me and asking me about Zynga. To clarify, I don&#8217;t work there any more. I left at the end of 2009.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/05/18/zynga-is-hiring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Major FontLabel update</title>
		<link>http://kevin.sb.org/2009/05/18/major-fontlabel-update/</link>
		<comments>http://kevin.sb.org/2009/05/18/major-fontlabel-update/#comments</comments>
		<pubDate>Mon, 18 May 2009 21:15:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[FontLabel]]></category>
		<category><![CDATA[iPhone SDK]]></category>
		<category><![CDATA[Obj-C]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=184</guid>
		<description><![CDATA[Last week I pushed out a major rewrite of FontLabel. This new version includes a category modeled after UIStringDrawing that enables you to draw text in custom fonts in your own drawRect: methods. It also includes accurate font metrics and uses more of the built-in UILabel properties. Contributions are welcome!]]></description>
				<content:encoded><![CDATA[<p>Last week I pushed out a major rewrite of <a href="http://github.com/zynga/FontLabel">FontLabel</a>. This new version includes a category modeled after UIStringDrawing that enables you to draw text in custom fonts in your own <code>drawRect:</code> methods. It also includes accurate font metrics and uses more of the built-in UILabel properties. Contributions are welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/05/18/major-fontlabel-update/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ExecTweets on the App Store</title>
		<link>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/</link>
		<comments>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/#comments</comments>
		<pubDate>Mon, 18 May 2009 21:10:42 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ExecTweets]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=180</guid>
		<description><![CDATA[My last iPhone contract app, ExecTweets for iPhone, is now on the App Store. This is the project that drove the creation of FeedParser (an open source Obj-C RSS parser). Anyway, it&#8217;s free, and if you like reading about business advice from top business execs, check it out!]]></description>
				<content:encoded><![CDATA[<p>My last iPhone contract app, <a href="http://exectweets.com">ExecTweets</a> for iPhone, is now on the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=314677692&#038;mt=8">App Store</a>. This is the project that drove the creation of <a href="http://github.com/kballard/feedparser">FeedParser</a> (an open source Obj-C RSS parser). Anyway, it&#8217;s free, and if you like reading about business advice from top business execs, check it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Starting a new job</title>
		<link>http://kevin.sb.org/2009/04/28/starting-a-new-job/</link>
		<comments>http://kevin.sb.org/2009/04/28/starting-a-new-job/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 00:03:53 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Job]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Zynga]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=178</guid>
		<description><![CDATA[This coming monday, I am going to stop being an iPhone contractor and start being a full-time employee of Zynga. While there, I will be working on developing iPhone games.]]></description>
				<content:encoded><![CDATA[<p>This coming monday, I am going to stop being an iPhone contractor and start being a full-time employee of <a href="http://www.zynga.com">Zynga</a>. While there, I will be working on developing iPhone games.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/04/28/starting-a-new-job/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>DNS-SD Browser is on the AppStore</title>
		<link>http://kevin.sb.org/2009/04/10/dns-sd-browser-is-on-the-appstore/</link>
		<comments>http://kevin.sb.org/2009/04/10/dns-sd-browser-is-on-the-appstore/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 00:03:50 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[AppStore]]></category>
		<category><![CDATA[Bonjour Browser]]></category>
		<category><![CDATA[DNS-SD Browser]]></category>
		<category><![CDATA[iTunes]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=174</guid>
		<description><![CDATA[DNS-SD Browser has finally been released on the iTunes AppStore. DNS-SD Browser is the iPhone version of my popular desktop Bonjour Browser software. It enables you to view all of the Bonjour services on your local network as well as on wide-area Bonjour domains.]]></description>
				<content:encoded><![CDATA[<p><a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=305441017&#038;mt=8">DNS-SD Browser</a> has finally been released on the iTunes AppStore.</p>

<p>DNS-SD Browser is the iPhone version of my popular desktop <a href="http://tildesoft.com/Programs.html#BonjourBrowser">Bonjour Browser</a> software. It enables you to view all of the Bonjour services on your local network as well as on wide-area Bonjour domains.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/04/10/dns-sd-browser-is-on-the-appstore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebKit and handling of surrogate pairs in HTML entities</title>
		<link>http://kevin.sb.org/2008/11/10/webkit-and-handling-of-surrogate-pairs-in-html-entities/</link>
		<comments>http://kevin.sb.org/2008/11/10/webkit-and-handling-of-surrogate-pairs-in-html-entities/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 00:20:15 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[entities]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[surrogate pair]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[UTF-16]]></category>
		<category><![CDATA[WebKit]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=164</guid>
		<description><![CDATA[In this modern day, HTML entities can reference arbitrary unicode codepoints. For example, &#38;#x2603; is the entity for &#x2603;. Not surprisingly, WebKit appears uses UTF-16 internally to represent unicode strings, or at the very least when interpreting HTML entities. One of the big benefits of using UTF-16 is every character is represented by 2 bytes [...]]]></description>
				<content:encoded><![CDATA[<p>In this modern day, HTML entities can reference arbitrary unicode codepoints. For example, <code>&amp;#x2603;</code> is the entity for &#x2603;. Not surprisingly, WebKit appears uses UTF-16 internally to represent unicode strings, or at the very least when interpreting HTML entities. One of the big benefits of using UTF-16 is every character is represented by 2 bytes (the 16 in UTF-16 means 16 bits). Contrast this with UTF-8, where a single character can be represented by anywhere from 1 to 4 bytes, or UTF-32 where every character requires 4 bytes (i.e. twice as much as UTF-16). Clearly UTF-16 seems to be useful, as it&#8217;s not too much larger than UTF-8 for ASCII strings (only double the size), and you can jump to any character with a simple index into the string. However, one of the often-ignored aspects of UTF-16 is the surrogate pair. Unicode contains more than 0xFFFF bytes, and yet a single UTF-16 &#8220;character&#8221; (or unichar) can only reference up to U+FFFF. The solution to this is to take the codepoints in Unicode planes 1-16 (<code>U+10000</code> - <code>U+10FFFF</code>) and represent them as 2 unichars. This is a surrogate pair. You can find more information on this in the <a href="http://en.wikipedia.org/wiki/UTF-16#Encoding_of_characters_outside_the_BMP">wikipedia entry for UTF-16</a>, but to put it simply, a surrogate pair uses a range of codepoints that don&#8217;t represent real characters (<code>U+D800</code> - <code>U+DFFF</code>) and uses them in combination to represent all the characters in the other planes.</p>

<p>The reason this is interesting is because it exposes an interesting quirk as to how WebKit interprets HTML entities. WebKit properly converts entities that represent characters outside of plane 0 into a surrogate pair, such as <code>&amp;#x1D367;</code> (&#x1D367;). This gets converted into <code>0xD834DF67</code>. The quirk is if you give it the surrogate pair codepoints directly, it doesn&#8217;t realize they&#8217;re not real characters individually and passes them through unscathed, so that same character can be written as <code>&amp;#xD834;&amp;#xDF67;</code> (&#xD834;&#xDF67;). Now this doesn&#8217;t seem particularly harmful, except if you only write the first of these entities, WebKit will then get very confused. It will end up throwing away the entire rest of the line of rendered text. Interestingly, it starts displaying text again after a line break, even if it&#8217;s just an implicit line break.</p>

<p>The ideal behavior here is WebKit should just silently ignore any entities which reference a codepoint that&#8217;s part of a surrogate pair. The fact that it doesn&#8217;t really doesn&#8217;t hurt anything, but I thought it was worth documenting.</p>

<p><strong>Update:</strong> A question was raised on twitter about how surrogate pairs affect indexing into a UTF-16 string. I didn&#8217;t know the answer, and strangely, I couldn&#8217;t find information on how to handle it with google either, so I tested empirically. <code>NSString</code> uses UTF-16 internally, so it was a great way to test. And what I found was that each half of a surrogate pair is counted as a separate character. The <code>-length</code> of the <code>NSString</code> is increased by 2 when you add a surrogate pair, and <code>-substringFromIndex:</code> will happily split up the surrogate pair for you. Of course, if you do split a surrogate pair, then attempting to convert the <code>NSString</code> into another encoding, even with the simple <code>-UTF8String</code>, will return NULL as such a conversion is illegal (when you generate a unicode stream it has to be well-formed, and so you cannot generate a stream with half of a surrogate pair - and half of a surrogate pair in UTF-16 will be converted into a single invalid 3-byte UTF-8 sequence).</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/11/10/webkit-and-handling-of-surrogate-pairs-in-html-entities/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MediaLink</title>
		<link>http://kevin.sb.org/2008/07/13/medialink/</link>
		<comments>http://kevin.sb.org/2008/07/13/medialink/#comments</comments>
		<pubDate>Sun, 13 Jul 2008 05:45:39 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[MediaLink]]></category>
		<category><![CDATA[PS3]]></category>
		<category><![CDATA[sync]]></category>
		<category><![CDATA[TV]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=156</guid>
		<description><![CDATA[As a PlayStation™ 3 owner and an Apple TV owner, I can&#8217;t recommend MediaLink enough. It fills the missing link in my tv/movie-watching habits. Everything in my iTunes library I can watch on my Apple TV, but I have plenty of video files that iTunes can&#8217;t handle. Until recently, I&#8217;ve been forced to watch them [...]]]></description>
				<content:encoded><![CDATA[<p>As a PlayStation™ 3 owner and an <a href="http://www.apple.com/appletv">Apple TV</a> owner, I can&#8217;t recommend <a href="http://www.nullriver.com/products/medialink">MediaLink</a> enough. It fills the missing link in my tv/movie-watching habits. Everything in my iTunes library I can watch on my Apple TV, but I have plenty of video files that iTunes can&#8217;t handle. Until recently, I&#8217;ve been forced to watch them on my computer. But I have an HDTV for a reason, and I&#8217;d like to watch my shows there. <a href="http://www.nullriver.com/">Nullriver&#8217;s</a> <a href="http://www.nullriver.com/products/medialink">MediaLink</a> solves this problem. Anything that I can&#8217;t watch on my Apple TV, I can watch on my PS3, and it works flawlessly. I can fast-forward and rewind smoothly, I can jump to any point in the movie (using the PS3&#8217;s Go To feature), and it handles everything. Even when my computer lost wifi briefly (the microwave interferes with my desktop&#8217;s wifi), the video stream just paused until the wifi came back and then resumed as if nothing happened. If you own a PlayStation™ 3, you should go out and purchase <a href="http://www.nullriver.com/products/medialink">MediaLink</a> right now.</p>

<p>Disclaimer: I have no personal stake in <a href="http://www.nullriver.com/">Nullriver</a> or <a href="http://www.nullriver.com/products/medialink">MediaLink</a>, I am simply a happy customer.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/07/13/medialink/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->