Title: [193518] branches/safari-601-branch

Diff

Modified: branches/safari-601-branch/LayoutTests/ChangeLog (193517 => 193518)


--- branches/safari-601-branch/LayoutTests/ChangeLog	2015-12-05 18:30:10 UTC (rev 193517)
+++ branches/safari-601-branch/LayoutTests/ChangeLog	2015-12-05 18:30:14 UTC (rev 193518)
@@ -1,5 +1,22 @@
 2015-12-05  Matthew Hanson  <matthew_han...@apple.com>
 
+        Merge r189890. rdar://problem/23769735
+
+    2015-09-16  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+            Create a font which can be used for testing font features
+            https://bugs.webkit.org/show_bug.cgi?id=149237
+
+            Reviewed by Simon Fraser.
+
+            * css3/font-feature-settings-rendering-2-expected.html: Added.
+            * css3/font-feature-settings-rendering-2.html: Added.
+            * css3/resources/FontWithFeatures.otf: Added.
+            * platform/efl/TestExpectations:
+            * platform/win/TestExpectations:
+
+2015-12-05  Matthew Hanson  <matthew_han...@apple.com>
+
         Merge r188146. rdar://problem/23769732
 
     2015-08-07  Myles C. Maxfield  <mmaxfi...@apple.com>

Added: branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2-expected.html (0 => 193518)


--- branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2-expected.html	                        (rev 0)
+++ branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2-expected.html	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+    font-family: "FontFeaturesTest";
+    src: url("resources/FontWithFeatures.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+This tests that font features are able to be turned on and off as desired. It uses a special font
+designed specifically for this purpose. The test passes if you see a sequence of alternating check
+marks and X below.
+<div><span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+<span style="font-family: FontFeaturesTest;">BA</span>
+</div>
+</body>
+</html>

Added: branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2.html (0 => 193518)


--- branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2.html	                        (rev 0)
+++ branches/safari-601-branch/LayoutTests/css3/font-feature-settings-rendering-2.html	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+    font-family: "FontFeaturesTest";
+    src: url("resources/FontWithFeatures.otf") format("opentype");
+}
+</style>
+</head>
+<body>
+This tests that font features are able to be turned on and off as desired. It uses a special font
+designed specifically for this purpose. The test passes if you see a sequence of alternating check
+marks and X below.
+<div id="insertionpoint"></div>
+<script>
+var insertionpoint = document.getElementById("insertionpoint");
+function addElement(feature, c) {
+    ["0", "1"].map(function(state) {
+        var element = document.createElement("span");
+        element.textContent = c;
+        element.style.fontFamily = "FontFeaturesTest";
+        element.style.webkitFontFeatureSettings = '"' + feature + '" ' + state;
+        insertionpoint.appendChild(element);
+    });
+    insertionpoint.appendChild(document.createTextNode(" "));
+}
+addElement("liga", "C");
+addElement("clig", "D");
+addElement("dlig", "E");
+addElement("hlig", "F");
+addElement("calt", "G");
+addElement("subs", "H");
+addElement("sups", "I");
+addElement("smcp", "J");
+addElement("c2sc", "K");
+addElement("pcap", "L");
+addElement("c2pc", "M");
+addElement("unic", "N");
+addElement("titl", "O");
+addElement("onum", "P");
+addElement("pnum", "Q");
+addElement("tnum", "R");
+addElement("frac", "S");
+//addElement("afrc", "T");
+addElement("ordn", "U");
+addElement("zero", "V");
+addElement("hist", "W");
+addElement("jp78", "X");
+addElement("jp83", "Y");
+addElement("jp90", "Z");
+addElement("jp04", "a");
+addElement("smpl", "b");
+addElement("trad", "c");
+addElement("fwid", "d");
+addElement("pwid", "e");
+addElement("ruby", "f");
+</script>
+</body>
+</html>

Added: branches/safari-601-branch/LayoutTests/css3/resources/FontWithFeatures.otf (0 => 193518)


--- branches/safari-601-branch/LayoutTests/css3/resources/FontWithFeatures.otf	                        (rev 0)
+++ branches/safari-601-branch/LayoutTests/css3/resources/FontWithFeatures.otf	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,19 @@
+OTTO
+\x80 CFF \x94[\xA9D\xAC";GSUB\xC5b\xBB\xFE"\xE8\x94OS/2H\xE0Yb'|dcmap\xD5\xAF'\xE0jheadeD\xF8(L6hheag7(\x84$hmtx(\xA8\xD4maxpk)| name\xA8)\x9C$post)\xC0 
+MylesFont9\x87\x87q\xDA
+MylesFont	
++ !"#$%&'()*+,-./012345I\xA7G\xE7\x87'\xC7g\xA7G\xE7\x87'\xC7	g
+
+\xA7G\xE7\x87+'+\xC7g\xA7G\xE7\x87'\xC7g\xA7G\xE7\x87'\xC7g\xA7G\xE7\x87'\xC7g\xA7G\xE7 \x87\xFF\xFF\xFF\xFF\xC8\xFF\xC8\xFF\xFFX\xFFX\xFF\xFF\xFF\xFD\xA8\xFF\xFD\xA8\xFF\xFF\xFF\xFF\xFF\xC8\xFF\xF4\xFF2\xFF2\xFF\xFA\xFF\xFF\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFE>\xFF\xFE>\xFF\xFE\xD4\xFF,\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\x
 FF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xF
 F\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE
 \xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp
 \xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90
 \xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp
 \xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp
 \xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF
 \xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF
 2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x
 90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x
 90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\x
 FEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\
 x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF
 2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2
 \xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90
 \xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp\xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp
 \xFF\xFF\xFF\xFF\xF4\xFF&\xFF\x90\xFF\x90\xFF2\xFF\xFF\xCE\xFF\xFEp\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFF\xCE\xFF\xFF\xCE\xFF\xFEp\xFF\x90\xFF\xFEp\xFF\xFEp\xFF\xFF\xCE\xFF2\xFF\x90\xFF\x90\xFF\xFEp\xFF\x90\xFF2\xFF2\xFF\x90\xFF\xFEp
+X\xC2DFLT\xFF\xFF	
++liga\xB6clig\xBCdlig\xC2hlig\xC8calt\xCEsubs\xD4sups\xDAsmcp\xE0c2sc\xE6pcap\xECc2pc\xF2unic\xF8titl\xFEonumpnum
+tnumfracafrcordn"zero(hist.jp784jp83:jp90@jp04FsmplLtradRfwidXpwid^rubyd	
++>FNV^fnv~\x86\x8E\x96\x9E\xA6\xAE\xB6\xBE\xC6\xCE\xD6\xDE\xE6\xEE\xF6\xFE&\xF0\xF6\xFC &,28>DJPV\bhntz\x80\x86\x8C\x92\x98\x9E	
++ \xF4TKBW\xFF\xFFf\xFF\xFC\xFF\xFF \xFF\xFFD
+(AZaz&Zz\xFF\xFFAa\xFF\xFF\xFF\xDA\xFF\xA0y\xF6\x9C_<\xF5f55\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF5	MylesFont
\ No newline at end of file

Modified: branches/safari-601-branch/LayoutTests/platform/efl/TestExpectations (193517 => 193518)


--- branches/safari-601-branch/LayoutTests/platform/efl/TestExpectations	2015-12-05 18:30:10 UTC (rev 193517)
+++ branches/safari-601-branch/LayoutTests/platform/efl/TestExpectations	2015-12-05 18:30:14 UTC (rev 193518)
@@ -81,6 +81,8 @@
 # This test has been added for ios port since r185842.
 fast/text/arabic-times-new-roman.html [ Skip ]
 
+css3/font-feature-settings-rendering-2.html [ Skip ]
+
 # ----------------------------------------
 # Tests which also fail in other platforms
 # ----------------------------------------

Modified: branches/safari-601-branch/LayoutTests/platform/win/TestExpectations (193517 => 193518)


--- branches/safari-601-branch/LayoutTests/platform/win/TestExpectations	2015-12-05 18:30:10 UTC (rev 193517)
+++ branches/safari-601-branch/LayoutTests/platform/win/TestExpectations	2015-12-05 18:30:14 UTC (rev 193518)
@@ -458,6 +458,7 @@
 
 # Font feature settings is not implemented.
 css3/font-feature-settings-rendering.html [ Skip ]
+css3/font-feature-settings-rendering-2.html [ Skip ]
 
 # TODO HiDPI tests require test infrastructure enhancements (e.g. testRunner.setBackingScaleFactor)
 # https://bugs.webkit.org/show_bug.cgi?id=87919

Modified: branches/safari-601-branch/Tools/ChangeLog (193517 => 193518)


--- branches/safari-601-branch/Tools/ChangeLog	2015-12-05 18:30:10 UTC (rev 193517)
+++ branches/safari-601-branch/Tools/ChangeLog	2015-12-05 18:30:14 UTC (rev 193518)
@@ -1,3 +1,118 @@
+2015-12-05  Matthew Hanson  <matthew_han...@apple.com>
+
+        Merge r189890. rdar://problem/23769735
+
+    2015-09-16  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+            Create a font which can be used for testing font features
+            https://bugs.webkit.org/show_bug.cgi?id=149237
+
+            Reviewed by Simon Fraser.
+
+            This patch adds a new project in the Tools/ directory which generates a font which can
+            be used for testing font features. This is a standalone project consisting of two files:
+            1. A file which actually generates the byte vector representing the font. This file has
+            a single public function: std::vector<uint8_t> generateFont(). This file is not platform
+            specific, and only relies on the C++ STL.
+            2. A file with a main() which calls generateFont() and writes out the font, as well as
+            uses the font to render some demonstration text into a .png file. This file is platform
+            specific.
+
+            The font itself only supports the following characters:
+            ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+            However, the shape of these letters are either an X or a check mark.
+
+            The letter "A" always is a check mark.
+            The letter "B" always is an X.
+            Without any font features turned on, the rest of the letters are shown as X.
+
+            Each font feature has an letter associated with it. When the font feature is enabled,
+            that letter is shown as a check mark. For example, when "smcp" is enabled, "J" is shown
+            as a check mark.
+
+            Here are the mappings of font features to letters:
+            liga: C
+            clig: D
+            dlig: E
+            hlig: F
+            calt: G
+            subs: H
+            sups: I
+            smcp: J
+            c2sc: K
+            pcap: L
+            c2pc: M
+            unic: N
+            titl: O
+            onum: P
+            pnum: Q
+            tnum: R
+            frac: S
+            afrc: T
+            ordn: U
+            zero: V
+            hist: W
+            jp78: X
+            jp83: Y
+            jp90: Z
+            jp04: a
+            smpl: b
+            trad: c
+            fwid: d
+            pwid: e
+            ruby: f
+
+            * FontWithFeatures/FontWithFeatures.xcodeproj/project.pbxproj: Added.
+            * FontWithFeatures/FontWithFeatures/FontCreator.cpp: Added.
+            (integralLog2):
+            (roundDownToPowerOfTwo):
+            (isFourByteAligned):
+            (clampTo):
+            (append32):
+            (writeCFFEncodedNumber):
+            (CFFBuilder::CFFBuilder):
+            (CFFBuilder::takeResult):
+            (CFFBuilder::moveTo):
+            (CFFBuilder::lineTo):
+            (CFFBuilder::curveToCubic):
+            (CFFBuilder::closePath):
+            (CFFBuilder::writePoint):
+            (generateBoxCharString):
+            (generateCheckCharString):
+            (generateXCharString):
+            (charStringForGlyph):
+            (Generator::generate):
+            (Generator::Placeholder::Placeholder):
+            (Generator::Placeholder::populate):
+            (Generator::Placeholder::~Placeholder):
+            (Generator::placeholder):
+            (Generator::append16):
+            (Generator::append32):
+            (Generator::append32BitCode):
+            (Generator::overwrite16):
+            (Generator::overwrite32):
+            (Generator::appendCFFTable):
+            (Generator::appendSubstitutionSubtable):
+            (Generator::appendScriptSubtable):
+            (Generator::appendGSUBTable):
+            (Generator::appendOS2Table):
+            (Generator::appendFormat12CMAPTable):
+            (Generator::appendFormat4CMAPTable):
+            (Generator::appendCMAPTable):
+            (Generator::appendHEADTable):
+            (Generator::appendHHEATable):
+            (Generator::appendHMTXTable):
+            (Generator::appendMAXPTable):
+            (Generator::appendNAMETable):
+            (Generator::appendPOSTTable):
+            (Generator::calculateChecksum):
+            (Generator::appendTable):
+            (generateFont):
+            * FontWithFeatures/FontWithFeatures/FontCreator.h: Added.
+            * FontWithFeatures/FontWithFeatures/main.cpp: Added.
+            (drawTextWithFeature):
+            (main):
+
 2015-10-27  Matthew Hanson  <matthew_han...@apple.com>
 
         Merge r191395. rdar://problem/22847057

Added: branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.cpp (0 => 193518)


--- branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.cpp	                        (rev 0)
+++ branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.cpp	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,788 @@
+//
+//  FontCreator.cpp
+//  FontWithFeatures
+//
+//  Created by Litherum on 9/15/15.
+//  Copyright © 2015 Litherum. All rights reserved.
+//
+
+#include "FontCreator.h"
+
+#include <array>
+#include <cassert>
+#include <string>
+
+static const size_t headerSize = 12;
+static const size_t directoryEntrySize = 16;
+static const int16_t unitsPerEm = 1024;
+static const uint16_t numGlyphs = 26 * 2 + 1;
+
+static inline uint16_t integralLog2(uint16_t x)
+{
+    uint16_t result = 0;
+    while (x >>= 1)
+        ++result;
+    return result;
+}
+
+static inline uint16_t roundDownToPowerOfTwo(uint16_t x)
+{
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    return (x >> 1) + 1;
+}
+
+static inline bool isFourByteAligned(size_t x)
+{
+    return !(x & 3);
+}
+
+// Assumption: T2 can hold every value that a T1 can hold.
+template<typename T1, typename T2> static inline T1 clampTo(T2 x)
+{
+    x = std::min(x, static_cast<T2>(std::numeric_limits<T1>::max()));
+    x = std::max(x, static_cast<T2>(std::numeric_limits<T1>::min()));
+    return static_cast<T1>(x);
+}
+
+template <typename V>
+static inline void append32(V& result, uint32_t value)
+{
+    result.push_back(value >> 24);
+    result.push_back(value >> 16);
+    result.push_back(value >> 8);
+    result.push_back(value);
+}
+
+template <typename V>
+static void writeCFFEncodedNumber(V& vector, float number)
+{
+    vector.push_back(0xFF);
+    // Convert to 16.16 fixed-point
+    append32(vector, clampTo<int32_t>(number * 0x10000));
+}
+
+static const char rLineTo = 0x05;
+static const char rrCurveTo = 0x08;
+static const char endChar = 0x0e;
+static const char rMoveTo = 0x15;
+
+class CFFBuilder {
+public:
+    CFFBuilder(float width, std::pair<float, float> origin)
+    {
+        writeCFFEncodedNumber(result, width);
+        writeCFFEncodedNumber(result, origin.first);
+        writeCFFEncodedNumber(result, origin.second);
+        result.push_back(rMoveTo);
+    }
+
+    std::vector<uint8_t> takeResult()
+    {
+        result.push_back(endChar);
+        return std::move(result);
+    }
+
+    void moveTo(std::pair<float, float> targetPoint, bool closed)
+    {
+        if (closed && !result.empty())
+            closePath();
+
+        std::pair<float, float> destination = targetPoint;
+
+        writePoint(destination);
+        result.push_back(rMoveTo);
+
+        startingPoint = current;
+    }
+
+    void lineTo(std::pair<float, float> targetPoint)
+    {
+        std::pair<float, float> destination = targetPoint;
+
+        writePoint(destination);
+        result.push_back(rLineTo);
+    }
+
+    void curveToCubic(std::pair<float, float> point1, std::pair<float, float> point2, std::pair<float, float> targetPoint)
+    {
+        std::pair<float, float> destination1 = point1;
+        std::pair<float, float> destination2 = point2;
+        std::pair<float, float> destination3 = targetPoint;
+
+        writePoint(destination1);
+        writePoint(destination2);
+        writePoint(destination3);
+        result.push_back(rrCurveTo);
+    }
+
+    void closePath()
+    {
+        if (current != startingPoint)
+            lineTo(startingPoint);
+    }
+
+private:
+    void writePoint(std::pair<float, float> destination)
+    {
+        std::pair<float, float> delta = std::make_pair(destination.first - current.first, destination.second - current.second);
+        writeCFFEncodedNumber(result, delta.first);
+        writeCFFEncodedNumber(result, delta.second);
+
+        current = destination;
+    }
+
+    std::vector<uint8_t> result;
+    std::pair<float, float> startingPoint;
+    std::pair<float, float> current;
+};
+
+std::vector<uint8_t> generateBoxCharString()
+{
+    CFFBuilder builder(unitsPerEm, std::make_pair(0.f, 0.f));
+    builder.moveTo(std::make_pair(200.f, 200.f), false);
+    builder.lineTo(std::make_pair(200.f, 800.f));
+    builder.lineTo(std::make_pair(800.f, 800.f));
+    builder.lineTo(std::make_pair(800.f, 200.f));
+    builder.closePath();
+    return builder.takeResult();
+}
+
+std::vector<uint8_t> generateCheckCharString()
+{
+    CFFBuilder builder(unitsPerEm, std::make_pair(0.f, 0.f));
+    builder.moveTo(std::make_pair(200.f, 500.f), false);
+    builder.lineTo(std::make_pair(250.f, 550.f));
+    builder.lineTo(std::make_pair(500.f, 300.f));
+    builder.lineTo(std::make_pair(900.f, 700.f));
+    builder.lineTo(std::make_pair(950.f, 650.f));
+    builder.lineTo(std::make_pair(500.f, 200.f));
+    builder.closePath();
+    return builder.takeResult();
+}
+
+std::vector<uint8_t> generateXCharString()
+{
+    CFFBuilder builder(unitsPerEm, std::make_pair(0.f, 0.f));
+    builder.moveTo(std::make_pair(500.0f, 550.0f), false);
+    builder.lineTo(std::make_pair(900.f, 950.f));
+    builder.lineTo(std::make_pair(950.f, 900.f));
+    builder.lineTo(std::make_pair(550.f, 500.f));
+    builder.lineTo(std::make_pair(950.f, 100.f));
+    builder.lineTo(std::make_pair(900.f,  50.f));
+    builder.lineTo(std::make_pair(500.f, 450.f));
+    builder.lineTo(std::make_pair(100.f,  50.f));
+    builder.lineTo(std::make_pair(50.f , 100.f));
+    builder.lineTo(std::make_pair(450.f, 500.f));
+    builder.lineTo(std::make_pair(50.f , 900.f));
+    builder.lineTo(std::make_pair(100.f, 950.f));
+    builder.closePath();
+    return builder.takeResult();
+}
+
+std::vector<uint8_t>& charStringForGlyph(uint16_t glyph, std::vector<uint8_t>& boxCharString, std::vector<uint8_t>& checkCharString, std::vector<uint8_t>& xCharString)
+{
+    if (!glyph)
+        return boxCharString;
+    if (glyph == 1)
+        return checkCharString;
+    return xCharString;
+}
+
+class Generator {
+public:
+    std::vector<uint8_t> generate()
+    {
+        uint16_t numTables = 10;
+        uint16_t roundedNumTables = roundDownToPowerOfTwo(numTables);
+        uint16_t searchRange = roundedNumTables * 16; // searchRange: "(Maximum power of 2 <= numTables) x 16."
+
+        result.push_back('O');
+        result.push_back('T');
+        result.push_back('T');
+        result.push_back('O');
+        append16(numTables);
+        append16(searchRange);
+        append16(integralLog2(roundedNumTables)); // entrySelector: "Log2(maximum power of 2 <= numTables)."
+        append16(numTables * 16 - searchRange); // rangeShift: "NumTables x 16-searchRange."
+
+        assert(result.size() == headerSize);
+
+        // Leave space for the directory entries.
+        for (size_t i = 0; i < directoryEntrySize * numTables; ++i)
+            result.push_back(0);
+
+        appendTable("CFF ", &Generator::appendCFFTable);
+        appendTable("GSUB", &Generator::appendGSUBTable);
+        appendTable("OS/2", &Generator::appendOS2Table);
+        appendTable("cmap", &Generator::appendCMAPTable);
+        auto headTableOffset = result.size();
+        appendTable("head", &Generator::appendHEADTable);
+        appendTable("hhea", &Generator::appendHHEATable);
+        appendTable("hmtx", &Generator::appendHMTXTable);
+        appendTable("maxp", &Generator::appendMAXPTable);
+        appendTable("name", &Generator::appendNAMETable);
+        appendTable("post", &Generator::appendPOSTTable);
+
+        assert(numTables == m_tablesAppendedCount);
+
+        // checksumAdjustment: "To compute: set it to 0, calculate the checksum for the 'head' table and put it in the table directory,
+        // sum the entire font as uint32, then store B1B0AFBA - sum. The checksum for the 'head' table will now be wrong. That is OK."
+        overwrite32(headTableOffset + 8, 0xB1B0AFBAU - calculateChecksum(0, result.size()));
+        return std::move(result);
+    }
+
+private:
+    class Placeholder {
+    public:
+        Placeholder(Generator& generator, size_t baseOfOffset)
+            : generator(generator)
+            , baseOfOffset(baseOfOffset)
+            , location(generator.result.size())
+        {
+            generator.append16(0);
+        }
+
+        Placeholder(Placeholder&& other)
+            : generator(other.generator)
+            , baseOfOffset(other.baseOfOffset)
+            , location(other.location)
+            , active(other.active)
+        {
+            other.active = false;
+        }
+
+        void populate()
+        {
+            assert(active);
+            size_t delta = generator.result.size() - baseOfOffset;
+            assert(delta < std::numeric_limits<uint16_t>::max());
+            generator.overwrite16(location, delta);
+            active = false;
+        }
+
+        ~Placeholder()
+        {
+            assert(!active);
+        }
+
+    private:
+        Generator& generator;
+        const size_t baseOfOffset;
+        const size_t location;
+        bool active { true };
+    };
+
+    Placeholder placeholder(size_t baseOfOffset)
+    {
+        return Placeholder(*this, baseOfOffset);
+    }
+
+    void append16(uint16_t value)
+    {
+        result.push_back(value >> 8);
+        result.push_back(value);
+    }
+
+    void append32(uint32_t value)
+    {
+        ::append32(result, value);
+    }
+
+    void append32BitCode(const char code[4])
+    {
+        result.push_back(code[0]);
+        result.push_back(code[1]);
+        result.push_back(code[2]);
+        result.push_back(code[3]);
+    }
+
+    void overwrite16(size_t location, uint16_t value)
+    {
+        assert(result.size() >= location + 2);
+        result[location] = value >> 8;
+        result[location + 1] = value;
+    }
+
+    void overwrite32(size_t location, uint32_t value)
+    {
+        assert(result.size() >= location + 4);
+        result[location] = value >> 24;
+        result[location + 1] = value >> 16;
+        result[location + 2] = value >> 8;
+        result[location + 3] = value;
+    }
+    
+    void appendCFFTable()
+    {
+        auto startingOffset = result.size();
+
+        // Header
+        result.push_back(1); // Major version
+        result.push_back(0); // Minor version
+        result.push_back(4); // Header size
+        result.push_back(4); // Offsets within CFF table are 4 bytes long
+
+        // Name INDEX
+        std::string fontName = "MylesFont";
+        append16(1); // INDEX contains 1 element
+        result.push_back(4); // Offsets in this INDEX are 4 bytes long
+        append32(1); // 1-index offset of name data
+        append32(static_cast<uint32_t>(fontName.length() + 1)); // 1-index offset just past end of name data
+        for (char c : fontName)
+            result.push_back(c);
+
+        const char operand32Bit = 29;
+        const char fullNameKey = 2;
+        const char familyNameKey = 3;
+        const char fontBBoxKey = 5;
+        const char charsetIndexKey = 15;
+        const char charstringsIndexKey = 17;
+        const char privateDictIndexKey = 18;
+        const uint32_t userDefinedStringStartIndex = 391;
+        const unsigned sizeOfTopIndex = 56;
+
+        // Top DICT INDEX.
+        append16(1); // INDEX contains 1 element
+        result.push_back(4); // Offsets in this INDEX are 4 bytes long
+        append32(1); // 1-index offset of DICT data
+        append32(1 + sizeOfTopIndex); // 1-index offset just past end of DICT data
+
+        // DICT information
+        size_t topDictStart = result.size();
+        result.push_back(operand32Bit);
+        append32(userDefinedStringStartIndex);
+        result.push_back(fullNameKey);
+        result.push_back(operand32Bit);
+        append32(userDefinedStringStartIndex);
+        result.push_back(familyNameKey);
+        result.push_back(operand32Bit);
+        append32(clampTo<int32_t>(0)); // Bounding box x
+        result.push_back(operand32Bit);
+        append32(clampTo<int32_t>(0)); // Bounding box y
+        result.push_back(operand32Bit);
+        append32(clampTo<int32_t>(unitsPerEm)); // Bounding box max x
+        result.push_back(operand32Bit);
+        append32(clampTo<int32_t>(unitsPerEm)); // Bounding box max y
+        result.push_back(fontBBoxKey);
+        result.push_back(operand32Bit);
+        size_t charsetOffsetLocation = result.size();
+        append32(0); // Offset of Charset info. Will be overwritten later.
+        result.push_back(charsetIndexKey);
+        result.push_back(operand32Bit);
+        size_t charstringsOffsetLocation = result.size();
+        append32(0); // Offset of CharStrings INDEX. Will be overwritten later.
+        result.push_back(charstringsIndexKey);
+        result.push_back(operand32Bit);
+        append32(0); // 0-sized private dict
+        result.push_back(operand32Bit);
+        append32(0); // no location for private dict
+        result.push_back(privateDictIndexKey); // Private dict size and offset
+        assert(result.size() == topDictStart + sizeOfTopIndex);
+
+        // String INDEX
+        append16(1); // Number of elements in INDEX
+        result.push_back(4); // Offsets in this INDEX are 4 bytes long
+        uint32_t offset = 1;
+        append32(offset);
+        offset += fontName.length();
+        append32(offset);
+        for (char c : fontName)
+            result.push_back(c);
+
+        append16(0); // Empty subroutine INDEX
+    
+        // Charset info
+        overwrite32(charsetOffsetLocation, static_cast<uint32_t>(result.size() - startingOffset));
+        result.push_back(0);
+        for (int i = 1; i < numGlyphs; ++i)
+            append16(i);
+
+        // CharStrings INDEX
+        std::vector<uint8_t> boxCharString = generateBoxCharString();
+        std::vector<uint8_t> checkCharString = generateCheckCharString();
+        std::vector<uint8_t> xCharString = generateXCharString();
+        assert(numGlyphs > 26);
+        overwrite32(charstringsOffsetLocation, static_cast<uint32_t>(result.size() - startingOffset));
+        append16(numGlyphs);
+        result.push_back(4); // Offsets in this INDEX are 4 bytes long
+        offset = 1;
+        append32(offset);
+        for (uint16_t glyph = 0; glyph < numGlyphs; ++glyph) {
+            offset += charStringForGlyph(glyph, boxCharString, checkCharString, xCharString).size();
+            append32(offset);
+        }
+        for (uint16_t glyph = 0; glyph < numGlyphs; ++glyph) {
+            std::vector<uint8_t>& charString = charStringForGlyph(glyph, boxCharString, checkCharString, xCharString);
+            result.insert(result.end(), charString.begin(), charString.end());
+        }
+    }
+
+    void appendSubstitutionSubtable(size_t subtableRecordLocation, uint16_t iGetReplaced, uint16_t replacedWithMe)
+    {
+        overwrite16(subtableRecordLocation + 6, result.size() - subtableRecordLocation);
+        auto subtableLocation = result.size();
+        append16(2); // Format 2
+        append16(0); // Placeholder for offset to coverage table, relative to beginning of substitution table
+        append16(1); // GlyphCount
+        append16(replacedWithMe); // Substitute with this glyph.
+
+        // Coverage table
+        overwrite16(subtableLocation + 2, result.size() - subtableLocation);
+        append16(1); // CoverageFormat
+        append16(1); // GlyphCount
+        append16(iGetReplaced); // This glyph is covered in the coverage.
+    }
+
+    void appendScriptSubtable(uint16_t featureCount)
+    {
+        auto dfltScriptTableLocation = result.size();
+        append16(0); // Placeholder for offset of default language system table, relative to beginning of Script table
+        append16(0); // Number of following language system tables
+
+        // LangSys table
+        overwrite16(dfltScriptTableLocation, result.size() - dfltScriptTableLocation);
+        append16(0); // LookupOrder "= NULL ... reserved"
+        append16(0xFFFF); // No features are required
+        append16(featureCount); // Number of FeatureIndex values
+        for (uint16_t i = 0; i < featureCount; ++i)
+            append16(i); // Features indices
+    }
+
+    void appendGSUBTable()
+    {
+        std::vector<std::array<char, 5>> features {{"liga"}, {"clig"}, {"dlig"}, {"hlig"}, {"calt"}, {"subs"}, {"sups"}, {"smcp"}, {"c2sc"}, {"pcap"}, {"c2pc"}, {"unic"}, {"titl"}, {"onum"}, {"pnum"}, {"tnum"}, {"frac"}, {"afrc"}, {"ordn"}, {"zero"}, {"hist"}, {"jp78"}, {"jp83"}, {"jp90"}, {"jp04"}, {"smpl"}, {"trad"}, {"fwid"}, {"pwid"}, {"ruby"}};
+        auto tableLocation = result.size();
+        auto headerSize = 10;
+
+        append32(0x00010000); // Version
+        append16(headerSize); // Offset to ScriptList
+        Placeholder toFeatureList = placeholder(tableLocation);
+        Placeholder toLookupList = placeholder(tableLocation);
+        assert(tableLocation + headerSize == result.size());
+
+        // ScriptList
+        auto scriptListLocation = result.size();
+        append16(1); // Number of ScriptRecords
+        append32BitCode("DFLT");
+        append16(0); // Placeholder for offset of Script table, relative to beginning of ScriptList
+
+        overwrite16(scriptListLocation + 6, result.size() - scriptListLocation);
+        appendScriptSubtable(static_cast<uint16_t>(features.size()));
+
+        // FeatureList
+        toFeatureList.populate();
+        auto featureListLocation = result.size();
+        size_t featureListSize = 2 + 6 * features.size();
+        size_t featureTableSize = 6;
+        append16(features.size()); // FeatureCount
+        for (unsigned i = 0; i < features.size(); ++i) {
+            auto& code = features[i];
+            append32BitCode(code.data()); // Feature name
+            append16(featureListSize + featureTableSize * i); // Offset of feature table, relative to beginning of FeatureList table
+        }
+        assert(featureListLocation + featureListSize == result.size());
+
+        for (unsigned i = 0; i < features.size(); ++i) {
+            auto featureTableStart = result.size();
+            append16(0); // FeatureParams "= NULL ... reserved"
+            append16(1); // LookupCount
+            append16(i); // LookupListIndex
+            assert(featureTableStart + featureTableSize == result.size());
+        }
+
+        // LookupList
+        toLookupList.populate();
+        auto lookupListLocation = result.size();
+        append16(features.size()); // LookupCount
+        for (unsigned i = 0; i < features.size(); ++i)
+            append16(0); // Placeholder for offset to lookup table, relative to beginning of LookupList
+        size_t subtableRecordLocations[features.size()];
+        for (unsigned i = 0; i < features.size(); ++i) {
+            subtableRecordLocations[i] = result.size();
+            overwrite16(lookupListLocation + 2 + 2 * i, result.size() - lookupListLocation);
+            append16(1); // Type 1: "Replace one glyph with one glyph"
+            append16(0); // LookupFlag
+            append16(1); // SubTableCount
+            append16(0); // Placeholder for offset to subtable, relative to beginning of Lookup table
+        }
+
+        for (unsigned i = 0; i < features.size(); ++i)
+            appendSubstitutionSubtable(subtableRecordLocations[i], 3 + i, 1);
+    }
+
+    void appendOS2Table()
+    {
+        append16(2); // Version
+        append16(clampTo<int16_t>(unitsPerEm)); // Average advance
+        append16(clampTo<uint16_t>(500)); // Weight class
+        append16(5); // Width class
+        append16(0); // Protected font
+        // WebKit handles these superscripts and subscripts
+        append16(0); // Subscript X Size
+        append16(0); // Subscript Y Size
+        append16(0); // Subscript X Offset
+        append16(0); // Subscript Y Offset
+        append16(0); // Superscript X Size
+        append16(0); // Superscript Y Size
+        append16(0); // Superscript X Offset
+        append16(0); // Superscript Y Offset
+        append16(0); // Strikeout width
+        append16(0); // Strikeout Position
+        append16(0); // No classification
+
+        for (int i = 0; i < 10; ++i)
+            result.push_back(0);
+
+        for (int i = 0; i < 4; ++i)
+            append32(0); // "Bit assignments are pending. Set to 0"
+        append32(0x544B4257); // Font Vendor. "WBKT"
+        append16(0); // Font Patterns.
+        append16(0); // First unicode index
+        append16(0xFFFF); // Last unicode index
+        append16(clampTo<int16_t>(unitsPerEm)); // Typographical ascender
+        append16(clampTo<int16_t>(1)); // Typographical descender
+        append16(clampTo<int16_t>(unitsPerEm / 10)); // Typographical line gap
+        append16(clampTo<uint16_t>(unitsPerEm)); // Windows-specific ascent
+        append16(clampTo<uint16_t>(1)); // Windows-specific descent
+        append32(0xFF10FC07); // Bitmask for supported codepages (Part 1). Report all pages as supported.
+        append32(0x0000FFFF); // Bitmask for supported codepages (Part 2). Report all pages as supported.
+        append16(clampTo<int16_t>(unitsPerEm / 2)); // x-height
+        append16(clampTo<int16_t>(unitsPerEm)); // Cap-height
+        append16(0); // Default char
+        append16(' '); // Break character
+        append16(3); // Maximum context needed to perform font features
+        append16(3); // Smallest optical point size
+        append16(0xFFFF); // Largest optical point size
+    }
+
+    void appendFormat12CMAPTable()
+    {
+        // Braindead scheme: One segment for each character
+        auto subtableLocation = result.size();
+        append32(12 << 16); // Format 12
+        append32(0); // Placeholder for byte length
+        append32(0); // Language independent
+        append32(2); //  nGroups
+        append32('A'); // startCharCode
+        append32('Z'); // endCharCode
+        append32(1); // startGlyphCode
+        append32('a'); // startCharCode
+        append32('z'); // endCharCode
+        append32(27); // startGlyphCode
+        overwrite32(subtableLocation + 4, static_cast<uint32_t>(result.size() - subtableLocation));
+    }
+
+    void appendFormat4CMAPTable()
+    {
+        auto subtableLocation = result.size();
+        append16(4); // Format 4
+        append16(0); // Placeholder for length in bytes
+        append16(0); // Language independent
+        uint16_t segCount = 3;
+        append16(clampTo<uint16_t>(2 * segCount)); // segCountX2: "2 x segCount"
+        uint16_t originalSearchRange = roundDownToPowerOfTwo(segCount);
+        uint16_t searchRange = clampTo<uint16_t>(2 * originalSearchRange); // searchRange: "2 x (2**floor(log2(segCount)))"
+        append16(searchRange);
+        append16(integralLog2(originalSearchRange)); // entrySelector: "log2(searchRange/2)"
+        append16(clampTo<uint16_t>((2 * segCount) - searchRange)); // rangeShift: "2 x segCount - searchRange"
+
+        // Ending character codes
+        append16('Z');
+        append16('z');
+        append16(0xFFFF);
+
+        append16(0); // reserved
+
+        // Starting character codes
+        append16('A');
+        append16('a');
+        append16(0xFFFF);
+
+        // idDelta
+        append16(static_cast<uint16_t>(27) - static_cast<uint16_t>('A'));
+        append16(static_cast<uint16_t>(1) - static_cast<uint16_t>('a'));
+        append16(0x0001);
+
+        // idRangeOffset
+        append16(0); // idRangeOffset
+        append16(0);
+
+        // Fonts strive to hold 2^16 glyphs, but with the current encoding scheme, we write 8 bytes per codepoint into this subtable.
+        // Because the size of this subtable must be represented as a 16-bit number, we are limiting the number of glyphs we support to 2^13.
+        // FIXME: If we hit this limit in the wild, use a more compact encoding scheme for this subtable.
+        overwrite16(subtableLocation + 2, clampTo<uint16_t>(result.size() - subtableLocation));
+    }
+    
+    void appendCMAPTable()
+    {
+        auto startingOffset = result.size();
+        append16(0);
+        append16(3); // Number of subtables
+
+        append16(0); // Unicode
+        append16(3); // Unicode version 2.2+
+        append32(28); // Byte offset of subtable
+
+        append16(3); // Microsoft
+        append16(1); // Unicode BMP
+        auto format4OffsetLocation = result.size();
+        append32(0); // Byte offset of subtable
+
+        append16(3); // Microsoft
+        append16(10); // Unicode
+        append32(28); // Byte offset of subtable
+
+        appendFormat12CMAPTable();
+        overwrite32(format4OffsetLocation, static_cast<uint32_t>(result.size() - startingOffset));
+        appendFormat4CMAPTable();
+    }
+    
+    void appendHEADTable()
+    {
+        append32(0x00010000); // Version
+        append32(0x00010000); // Revision
+        append32(0); // Checksum placeholder; to be overwritten by the caller.
+        append32(0x5F0F3CF5); // Magic number.
+        append16((1 << 9) | 1);
+
+        append16(unitsPerEm);
+        append32(0); // First half of creation date
+        append32(0); // Last half of creation date
+        append32(0); // First half of modification date
+        append32(0); // Last half of modification date
+        append16(clampTo<int16_t>(0)); // bounding box x
+        append16(clampTo<int16_t>(0)); // bounding box y
+        append16(clampTo<int16_t>(unitsPerEm)); // bounding box max x
+        append16(clampTo<int16_t>(unitsPerEm)); // bounding box max y
+        append16(0); // Traits
+        append16(3); // Smallest readable size in pixels
+        append16(0); // Might contain LTR or RTL glyphs
+        append16(0); // Short offsets in the 'loca' table. However, OTF fonts don't have a 'loca' table so this is irrelevant
+        append16(0); // Glyph data format
+    }
+    
+    void appendHHEATable()
+    {
+        append32(0x00010000); // Version
+        append16(clampTo<int16_t>(unitsPerEm)); // ascent
+        append16(clampTo<int16_t>(1)); // descent
+        // WebKit SVG font rendering has hard coded the line gap to be 1/10th of the font size since 2008 (see r29719).
+        append16(clampTo<int16_t>(unitsPerEm / 10)); // line gap
+        append16(clampTo<uint16_t>(unitsPerEm)); // advance width max
+        append16(clampTo<int16_t>(0)); // Minimum left side bearing
+        append16(clampTo<int16_t>(0)); // Minimum right side bearing
+        append16(clampTo<int16_t>(unitsPerEm)); // X maximum extent
+        // Since WebKit draws the caret and ignores the following values, it doesn't matter what we set them to.
+        append16(1); // Vertical caret
+        append16(0); // Vertical caret
+        append16(0); // "Set value to 0 for non-slanted fonts"
+        append32(0); // Reserved
+        append32(0); // Reserved
+        append16(0); // Current format
+        append16(numGlyphs); // Number of advance widths in HMTX table
+    }
+    
+    void appendHMTXTable()
+    {
+        for (unsigned i = 0; i < numGlyphs; ++i) {
+            append16(clampTo<uint16_t>(unitsPerEm)); // horizontal advance
+            append16(clampTo<int16_t>(0)); // left side bearing
+        }
+    }
+    
+    void appendMAXPTable()
+    {
+        append32(0x00010000); // Version
+        append16(numGlyphs); // Number of glyphs
+        append16(0xFFFF); // Maximum number of points in non-compound glyph
+        append16(0xFFFF); // Maximum number of contours in non-compound glyph
+        append16(0xFFFF); // Maximum number of points in compound glyph
+        append16(0xFFFF); // Maximum number of contours in compound glyph
+        append16(2); // Maximum number of zones
+        append16(0); // Maximum number of points used in zone 0
+        append16(0); // Maximum number of storage area locations
+        append16(0); // Maximum number of function definitions
+        append16(0); // Maximum number of instruction definitions
+        append16(0); // Maximum stack depth
+        append16(0); // Maximum size of instructions
+        append16(numGlyphs); // Maximum number of glyphs referenced at top level
+        append16(0); // No compound glyphs
+    }
+    
+    void appendNAMETable()
+    {
+        std::string fontName = "MylesFont";
+
+        append16(0); // Format selector
+        append16(1); // Number of name records in table
+        append16(18); // Offset in bytes to the beginning of name character strings
+
+        append16(0); // Unicode
+        append16(3); // Unicode version 2.0 or later
+        append16(0); // Language
+        append16(1); // Name identifier. 1 = Font family
+        append16(fontName.length());
+        append16(0); // Offset into name data
+
+        for (auto codeUnit : fontName)
+            append16(codeUnit);
+    }
+    
+    void appendPOSTTable()
+    {
+        append32(0x00030000); // Format. Printing is undefined
+        append32(0); // Italic angle in degrees
+        append16(0); // Underline position
+        append16(0); // Underline thickness
+        append32(0); // Monospaced
+        append32(0); // "Minimum memory usage when a TrueType font is downloaded as a Type 42 font"
+        append32(0); // "Maximum memory usage when a TrueType font is downloaded as a Type 42 font"
+        append32(0); // "Minimum memory usage when a TrueType font is downloaded as a Type 1 font"
+        append32(0); // "Maximum memory usage when a TrueType font is downloaded as a Type 1 font"
+    }
+
+    uint32_t calculateChecksum(size_t startingOffset, size_t endingOffset) const
+    {
+        assert(isFourByteAligned(endingOffset - startingOffset));
+        uint32_t sum = 0;
+        for (size_t offset = startingOffset; offset < endingOffset; offset += 4) {
+            sum += static_cast<unsigned char>(result[offset + 3])
+                | (static_cast<unsigned char>(result[offset + 2]) << 8)
+                | (static_cast<unsigned char>(result[offset + 1]) << 16)
+                | (static_cast<unsigned char>(result[offset]) << 24);
+        }
+        return sum;
+    }
+
+    typedef void (Generator::*FontAppendingFunction)();
+    void appendTable(const char identifier[4], FontAppendingFunction appendingFunction)
+    {
+        size_t offset = result.size();
+        assert(isFourByteAligned(offset));
+        (this->*appendingFunction)();
+        size_t unpaddedSize = result.size() - offset;
+        while (!isFourByteAligned(result.size()))
+            result.push_back(0);
+        assert(isFourByteAligned(result.size()));
+        size_t directoryEntryOffset = headerSize + m_tablesAppendedCount * directoryEntrySize;
+        result[directoryEntryOffset] = identifier[0];
+        result[directoryEntryOffset + 1] = identifier[1];
+        result[directoryEntryOffset + 2] = identifier[2];
+        result[directoryEntryOffset + 3] = identifier[3];
+        overwrite32(directoryEntryOffset + 4, calculateChecksum(offset, result.size()));
+        overwrite32(directoryEntryOffset + 8, static_cast<uint32_t>(offset));
+        overwrite32(directoryEntryOffset + 12, static_cast<uint32_t>(unpaddedSize));
+        ++m_tablesAppendedCount;
+    }
+
+    unsigned m_tablesAppendedCount { 0 };
+    std::vector<uint8_t> result;
+};
+
+std::vector<uint8_t> generateFont()
+{
+    return Generator().generate();
+}

Added: branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.h (0 => 193518)


--- branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.h	                        (rev 0)
+++ branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/FontCreator.h	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,16 @@
+//
+//  FontCreator.hpp
+//  FontWithFeatures
+//
+//  Created by Litherum on 9/15/15.
+//  Copyright © 2015 Litherum. All rights reserved.
+//
+
+#ifndef FontCreator_h
+#define FontCreator_h
+
+#include <vector>
+
+std::vector<uint8_t> generateFont();
+
+#endif /* FontCreator_h */

Added: branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/main.cpp (0 => 193518)


--- branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/main.cpp	                        (rev 0)
+++ branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures/main.cpp	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,114 @@
+//
+//  main.cpp
+//  FontWithFeatures
+//
+//  Created by Litherum on 9/15/15.
+//  Copyright © 2015 Litherum. All rights reserved.
+//
+
+#include "FontCreator.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreServices/CoreServices.h>
+#include <CoreText/CoreText.h>
+#include <ImageIO/ImageIO.h>
+#include <fstream>
+
+void drawTextWithFeature(CGContextRef context, CTFontDescriptorRef fontDescriptor, CFStringRef feature, int value, CGPoint location)
+{
+    CGFloat fontSize = 25;
+    CGContextSetTextMatrix(context, CGAffineTransformScale(CGAffineTransformIdentity, 1, 1));
+    CGContextSetTextPosition(context, location.x, location.y);
+
+    CFNumberRef featureValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
+    CFTypeRef featureDictionaryKeys[] = { kCTFontOpenTypeFeatureTag, kCTFontOpenTypeFeatureValue };
+    CFTypeRef featureDictionaryValues[] = { feature, featureValue };
+    CFDictionaryRef featureDictionary = CFDictionaryCreate(kCFAllocatorDefault, featureDictionaryKeys, featureDictionaryValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFRelease(featureValue);
+
+    CFTypeRef featureSettingsValues[] = { featureDictionary };
+    CFArrayRef fontFeatureSettings = CFArrayCreate(kCFAllocatorDefault, featureSettingsValues, 1, &kCFTypeArrayCallBacks);
+    CFRelease(featureDictionary);
+
+    CFTypeRef fontDescriptorKeys[] = { kCTFontFeatureSettingsAttribute };
+    CFTypeRef fontDescriptorValues[] = { fontFeatureSettings };
+    CFDictionaryRef fontDescriptorAttributes = CFDictionaryCreate(kCFAllocatorDefault, fontDescriptorKeys, fontDescriptorValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CFRelease(fontFeatureSettings);
+
+    CTFontDescriptorRef modifiedFontDescriptor = CTFontDescriptorCreateCopyWithAttributes(fontDescriptor, fontDescriptorAttributes);
+    CFRelease(fontDescriptorAttributes);
+
+    CTFontRef font = CTFontCreateWithFontDescriptor(modifiedFontDescriptor, fontSize, nullptr);
+    CFRelease(modifiedFontDescriptor);
+
+    CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
+    CFStringAppend(string, feature);
+    CFStringAppend(string, value ? CFSTR("  (on)") : CFSTR(" (off)"));
+    CFStringAppend(string, CFSTR(": ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+
+    CGColorRef red = CGColorCreateGenericRGB(1, 0, 0, 1);
+    CFTypeRef lineKeys[] = { kCTForegroundColorAttributeName };
+    CFTypeRef lineValues[] = { red };
+    CFDictionaryRef lineAttributes = CFDictionaryCreate(kCFAllocatorDefault, lineKeys, lineValues, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    CGColorRelease(red);
+
+    CFAttributedStringRef attributedString = CFAttributedStringCreate(kCFAllocatorDefault, string, lineAttributes);
+    CFRelease(lineAttributes);
+    CFRelease(string);
+
+    CFMutableAttributedStringRef mutableAttributedString = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 0, attributedString);
+    CFRelease(attributedString);
+
+    CTFontRef monospaceFont = CTFontCreateWithName(CFSTR("Courier"), fontSize, nullptr);
+    CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(0, 12), kCTFontAttributeName, monospaceFont);
+    CFRelease(monospaceFont);
+
+    CFAttributedStringSetAttribute(mutableAttributedString, CFRangeMake(12, 52), kCTFontAttributeName, font);
+    CFRelease(font);
+
+    CTLineRef line = CTLineCreateWithAttributedString(mutableAttributedString);
+    CFRelease(mutableAttributedString);
+
+    CTLineDraw(line, context);
+    CFRelease(line);
+}
+
+int main(int argc, const char * argv[])
+{
+    size_t width = 2000;
+    size_t height = 2000;
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef context = CGBitmapContextCreate(nullptr, width, height, 8, width * 4, colorSpace, kCGImageAlphaNoneSkipLast);
+    CGColorSpaceRelease(colorSpace);
+    const std::vector<uint8_t> fontVector = generateFont();
+    std::ofstream outputFile("/Volumes/Data/home/mmaxfield/tmp/output.otf", std::ios::out | std::ios::binary);
+    for (uint8_t b : fontVector)
+        outputFile << b;
+    outputFile.close();
+    
+    CFDataRef fontData = CFDataCreate(kCFAllocatorDefault, fontVector.data(), fontVector.size());
+    CTFontDescriptorRef fontDescriptor = CTFontManagerCreateFontDescriptorFromData(fontData);
+    CFRelease(fontData);
+
+    CFTypeRef featureValues[] = { CFSTR("liga"), CFSTR("clig"), CFSTR("dlig"), CFSTR("hlig"), CFSTR("calt"), CFSTR("subs"), CFSTR("sups"), CFSTR("smcp"), CFSTR("c2sc"), CFSTR("pcap"), CFSTR("c2pc"), CFSTR("unic"), CFSTR("titl"), CFSTR("onum"), CFSTR("pnum"), CFSTR("tnum"), CFSTR("frac"), CFSTR("afrc"), CFSTR("ordn"), CFSTR("zero"), CFSTR("hist"), CFSTR("jp78"), CFSTR("jp83"), CFSTR("jp90"), CFSTR("jp04"), CFSTR("smpl"), CFSTR("trad"), CFSTR("fwid"), CFSTR("pwid"), CFSTR("ruby") };
+    CFArrayRef features = CFArrayCreate(kCFAllocatorDefault, featureValues, 30, &kCFTypeArrayCallBacks);
+
+    for (CFIndex i = 0; i < CFArrayGetCount(features); ++i) {
+        drawTextWithFeature(context, fontDescriptor, static_cast<CFStringRef>(CFArrayGetValueAtIndex(features, i)), 1, CGPointMake(25, 1950 - 50 * i));
+        drawTextWithFeature(context, fontDescriptor, static_cast<CFStringRef>(CFArrayGetValueAtIndex(features, i)), 0, CGPointMake(25, 1925 - 50 * i));
+    }
+
+    CFRelease(features);
+    CFRelease(fontDescriptor);
+    CGImageRef image = CGBitmapContextCreateImage(context);
+    CGContextRelease(context);
+    CFURLRef url = "" CFSTR("/Volumes/Data/home/mmaxfield/tmp/output.png"), kCFURLPOSIXPathStyle, FALSE);
+    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, nullptr);
+    CFRelease(url);
+    CGImageDestinationAddImage(imageDestination, image, nullptr);
+    CGImageRelease(image);
+    CGImageDestinationFinalize(imageDestination);
+    CFRelease(imageDestination);
+    return 0;
+}

Added: branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures.xcodeproj/project.pbxproj (0 => 193518)


--- branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures.xcodeproj/project.pbxproj	                        (rev 0)
+++ branches/safari-601-branch/Tools/FontWithFeatures/FontWithFeatures.xcodeproj/project.pbxproj	2015-12-05 18:30:14 UTC (rev 193518)
@@ -0,0 +1,268 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		C28626A61BA902B9001961D6 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28626A51BA902B9001961D6 /* main.cpp */; };
+		C28626AD1BA904F1001961D6 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28626AC1BA904F1001961D6 /* CoreGraphics.framework */; };
+		C28626AF1BA9062C001961D6 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28626AE1BA9062C001961D6 /* ImageIO.framework */; };
+		C28626B11BA906C1001961D6 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28626B01BA906C1001961D6 /* CoreFoundation.framework */; };
+		C28626B31BA906D1001961D6 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28626B21BA906D1001961D6 /* CoreServices.framework */; };
+		C28626B51BA907AE001961D6 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28626B41BA907AE001961D6 /* CoreText.framework */; };
+		C28626B81BA91762001961D6 /* FontCreator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28626B61BA91762001961D6 /* FontCreator.cpp */; settings = {ASSET_TAGS = (); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		C28626A01BA902B9001961D6 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		C28626A21BA902B9001961D6 /* FontWithFeatures */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FontWithFeatures; sourceTree = BUILT_PRODUCTS_DIR; };
+		C28626A51BA902B9001961D6 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+		C28626AC1BA904F1001961D6 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		C28626AE1BA9062C001961D6 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
+		C28626B01BA906C1001961D6 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+		C28626B21BA906D1001961D6 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
+		C28626B41BA907AE001961D6 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
+		C28626B61BA91762001961D6 /* FontCreator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontCreator.cpp; sourceTree = "<group>"; };
+		C28626B71BA91762001961D6 /* FontCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontCreator.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		C286269F1BA902B9001961D6 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C28626B51BA907AE001961D6 /* CoreText.framework in Frameworks */,
+				C28626B31BA906D1001961D6 /* CoreServices.framework in Frameworks */,
+				C28626B11BA906C1001961D6 /* CoreFoundation.framework in Frameworks */,
+				C28626AF1BA9062C001961D6 /* ImageIO.framework in Frameworks */,
+				C28626AD1BA904F1001961D6 /* CoreGraphics.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		C28626991BA902B9001961D6 = {
+			isa = PBXGroup;
+			children = (
+				C28626B41BA907AE001961D6 /* CoreText.framework */,
+				C28626B21BA906D1001961D6 /* CoreServices.framework */,
+				C28626B01BA906C1001961D6 /* CoreFoundation.framework */,
+				C28626AE1BA9062C001961D6 /* ImageIO.framework */,
+				C28626AC1BA904F1001961D6 /* CoreGraphics.framework */,
+				C28626A41BA902B9001961D6 /* FontWithFeatures */,
+				C28626A31BA902B9001961D6 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		C28626A31BA902B9001961D6 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				C28626A21BA902B9001961D6 /* FontWithFeatures */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		C28626A41BA902B9001961D6 /* FontWithFeatures */ = {
+			isa = PBXGroup;
+			children = (
+				C28626A51BA902B9001961D6 /* main.cpp */,
+				C28626B61BA91762001961D6 /* FontCreator.cpp */,
+				C28626B71BA91762001961D6 /* FontCreator.h */,
+			);
+			path = FontWithFeatures;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		C28626A11BA902B9001961D6 /* FontWithFeatures */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = C28626A91BA902B9001961D6 /* Build configuration list for PBXNativeTarget "FontWithFeatures" */;
+			buildPhases = (
+				C286269E1BA902B9001961D6 /* Sources */,
+				C286269F1BA902B9001961D6 /* Frameworks */,
+				C28626A01BA902B9001961D6 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = FontWithFeatures;
+			productName = FontWithFeatures;
+			productReference = C28626A21BA902B9001961D6 /* FontWithFeatures */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		C286269A1BA902B9001961D6 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0700;
+				ORGANIZATIONNAME = Litherum;
+				TargetAttributes = {
+					C28626A11BA902B9001961D6 = {
+						CreatedOnToolsVersion = 7.0;
+					};
+				};
+			};
+			buildConfigurationList = C286269D1BA902B9001961D6 /* Build configuration list for PBXProject "FontWithFeatures" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = C28626991BA902B9001961D6;
+			productRefGroup = C28626A31BA902B9001961D6 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				C28626A11BA902B9001961D6 /* FontWithFeatures */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		C286269E1BA902B9001961D6 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				C28626A61BA902B9001961D6 /* main.cpp in Sources */,
+				C28626B81BA91762001961D6 /* FontCreator.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		C28626A71BA902B9001961D6 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.11;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				_ONLY_ACTIVE_ARCH_ = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		C28626A81BA902B9001961D6 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.11;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		C28626AA1BA902B9001961D6 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		C28626AB1BA902B9001961D6 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		C286269D1BA902B9001961D6 /* Build configuration list for PBXProject "FontWithFeatures" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C28626A71BA902B9001961D6 /* Debug */,
+				C28626A81BA902B9001961D6 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C28626A91BA902B9001961D6 /* Build configuration list for PBXNativeTarget "FontWithFeatures" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C28626AA1BA902B9001961D6 /* Debug */,
+				C28626AB1BA902B9001961D6 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = C286269A1BA902B9001961D6 /* Project object */;
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to