@breakside/jskit 2022.22.3 → 2022.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/JS/XMLSerializer.js +9 -4
  3. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  4. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  5. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  6. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  7. package/Frameworks/Foundation.jsframework/JS/JSAttributedString.js +279 -6
  8. package/Frameworks/Foundation.jsframework/JS/JSFileManager+Node.js +2 -2
  9. package/Frameworks/Foundation.jsframework/JS/JSFont.js +39 -15
  10. package/Frameworks/Foundation.jsframework/JS/JSFontDescriptor+HTML.js +8 -0
  11. package/Frameworks/Foundation.jsframework/JS/JSFontDescriptor.js +105 -27
  12. package/Frameworks/Foundation.jsframework/JS/JSParagraphStyle.js +71 -0
  13. package/Frameworks/Foundation.jsframework/JS/JSTextAttachment.js +1 -1
  14. package/Frameworks/Foundation.jsframework/JS/JSTextContainer.js +56 -29
  15. package/Frameworks/Foundation.jsframework/JS/JSTextFrame.js +2 -32
  16. package/Frameworks/Foundation.jsframework/JS/JSTextFramesetter.js +125 -22
  17. package/Frameworks/Foundation.jsframework/JS/JSTextLayoutManager.js +11 -3
  18. package/Frameworks/Foundation.jsframework/JS/JSTextLine.js +4 -3
  19. package/Frameworks/Foundation.jsframework/JS/JSTextRun.js +5 -3
  20. package/Frameworks/Foundation.jsframework/JS/JSTextTypesetter.js +41 -25
  21. package/Frameworks/Foundation.jsframework/JS/JSZip.js +97 -76
  22. package/Frameworks/Foundation.jsframework/JS/String+JS.js +69 -0
  23. package/Frameworks/Foundation.jsframework/JS/UnicodeChar.js +8 -0
  24. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  25. package/Frameworks/Foundation.jsframework/sources.json +26 -22
  26. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  27. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  28. package/Info.json +2 -2
  29. package/Node/io.breakside.jskit-bundle.js +2 -2
  30. package/Node/jskit +8 -7
  31. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  32. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  33. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  34. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  35. package/Root/Frameworks/ChartKit/CHAxis.js +5 -5
  36. package/Root/Frameworks/ChartKit/CHPieChart.js +1 -1
  37. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  38. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  39. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  40. package/Root/Frameworks/DOM/Info.yaml +1 -1
  41. package/Root/Frameworks/DOM/XMLSerializer.js +9 -4
  42. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  43. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  44. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  45. package/Root/Frameworks/Foundation/JSAttributedString.js +279 -6
  46. package/Root/Frameworks/Foundation/JSFileManager+Node.js +2 -2
  47. package/Root/Frameworks/Foundation/JSFont.js +39 -15
  48. package/Root/Frameworks/Foundation/JSFontDescriptor+HTML.js +8 -0
  49. package/Root/Frameworks/Foundation/JSFontDescriptor.js +105 -27
  50. package/Root/Frameworks/Foundation/JSParagraphStyle.js +71 -0
  51. package/Root/Frameworks/Foundation/JSTextAttachment.js +1 -1
  52. package/Root/Frameworks/Foundation/JSTextContainer.js +56 -29
  53. package/Root/Frameworks/Foundation/JSTextFrame.js +2 -32
  54. package/Root/Frameworks/Foundation/JSTextFramesetter.js +125 -22
  55. package/Root/Frameworks/Foundation/JSTextLayoutManager.js +11 -3
  56. package/Root/Frameworks/Foundation/JSTextLine.js +4 -3
  57. package/Root/Frameworks/Foundation/JSTextRun.js +5 -3
  58. package/Root/Frameworks/Foundation/JSTextTypesetter.js +41 -25
  59. package/Root/Frameworks/Foundation/JSZip.js +97 -76
  60. package/Root/Frameworks/Foundation/String+JS.js +69 -0
  61. package/Root/Frameworks/Foundation/UnicodeChar.js +8 -0
  62. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  63. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  64. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  65. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  66. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  67. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  68. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  69. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  70. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  71. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  72. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  73. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  74. package/Root/Frameworks/UIKit/UIBasicAnimation.js +1 -1
  75. package/Root/Frameworks/UIKit/UIHTMLApplication.js +1 -1
  76. package/Root/Frameworks/UIKit/UIHTMLContentEditableTextInputManager.js +36 -0
  77. package/Root/Frameworks/UIKit/UIHTMLDisplayServer.js +1 -1
  78. package/Root/Frameworks/UIKit/UIHTMLTextField.js +1 -1
  79. package/Root/Frameworks/UIKit/UIHTMLTextFrame.js +19 -91
  80. package/Root/Frameworks/UIKit/UIHTMLTextFramesetter.js +52 -9
  81. package/Root/Frameworks/UIKit/UIHTMLTextLine.js +95 -30
  82. package/Root/Frameworks/UIKit/UIHTMLTextRun.js +22 -9
  83. package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +334 -459
  84. package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +16 -0
  85. package/Root/Frameworks/UIKit/UIImageLayer.js +14 -7
  86. package/Root/Frameworks/UIKit/UIScrollView.js +12 -0
  87. package/Root/Frameworks/UIKit/UISegmentedControl.js +6 -6
  88. package/Root/Frameworks/UIKit/UITextAttachmentView.js +1 -1
  89. package/Root/Frameworks/UIKit/UITextEditor.js +210 -25
  90. package/Root/Frameworks/UIKit/UITextField.js +58 -31
  91. package/Root/Frameworks/UIKit/UITextInput.js +3 -1
  92. package/Root/Frameworks/UIKit/UITextInputManager.js +2 -2
  93. package/Root/Frameworks/UIKit/UITextLayer.js +39 -26
  94. package/Root/Frameworks/UIKit/UITokenField.js +4 -4
  95. package/Root/Frameworks/UIKit/UIView.js +3 -1
  96. package/Root/Frameworks/UIKit/UIWindow.js +16 -3
  97. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  98. package/package.json +1 -1
@@ -16,6 +16,8 @@
16
16
  // #import "Javascript.js"
17
17
  // #import "JSObject.js"
18
18
  // #import "JSTextAttachment.js"
19
+ // #import "JSFont.js"
20
+ // #import "JSColor.js"
19
21
  'use strict';
20
22
 
21
23
  (function(){
@@ -40,6 +42,137 @@ JSClass("JSAttributedString", JSObject, {
40
42
  this._runs = [run];
41
43
  },
42
44
 
45
+ initFromDictionary: function(dictionary){
46
+ this._string = typeof(dictionary.string) === "string" ? dictionary.string : "";
47
+ this._runs = [];
48
+ var i, l;
49
+ var runDictionary;
50
+ var run;
51
+ var attributes;
52
+ var name;
53
+ var location = 0;
54
+ var length;
55
+ var maxLength = this._string.length;
56
+ var decodeAttribute = function(name, value){
57
+ switch (name){
58
+ case JSAttributedString.Attribute.font:
59
+ return JSAttributedString.AttributeDecoder.font(value);
60
+ case JSAttributedString.Attribute.textColor:
61
+ case JSAttributedString.Attribute.backgroundColor:
62
+ return JSAttributedString.AttributeDecoder.color(value);
63
+ case JSAttributedString.Attribute.link:
64
+ return JSAttributedString.AttributeDecoder.url(value);
65
+ case JSAttributedString.Attribute.cursor:
66
+ return JSAttributedString.AttributeDecoder.skip(value);
67
+ case JSAttributedString.Attribute.attachment:
68
+ // TODO:
69
+ return JSAttributedString.AttributeDecoder.skip(value);
70
+ case JSAttributedString.Attribute.maskCharacter:
71
+ case JSAttributedString.Attribute.paragraphStyleName:
72
+ return JSAttributedString.AttributeDecoder.string(value);
73
+ case JSAttributedString.Attribute.bold:
74
+ case JSAttributedString.Attribute.italic:
75
+ case JSAttributedString.Attribute.underline:
76
+ case JSAttributedString.Attribute.strike:
77
+ return JSAttributedString.AttributeDecoder.boolean(value);
78
+ case JSAttributedString.Attribute.lineHeightMultiple:
79
+ case JSAttributedString.Attribute.lineSpacing:
80
+ case JSAttributedString.Attribute.paragraphSpacing:
81
+ case JSAttributedString.Attribute.beforeParagraphSpacing:
82
+ case JSAttributedString.Attribute.firstLineHeadIndent:
83
+ case JSAttributedString.Attribute.headIndent:
84
+ case JSAttributedString.Attribute.tailIndent:
85
+ case JSAttributedString.Attribute.minimumLineHeight:
86
+ return JSAttributedString.AttributeDecoder.number(value);
87
+ case JSAttributedString.Attribute.textAlignment:
88
+ return JSAttributedString.AttributeDecoder.enumValue(JSTextAlignment)(value);
89
+ case JSAttributedString.Attribute.lineBreakMode:
90
+ return JSAttributedString.AttributeDecoder.enumName(JSLineBreakMode)(value);
91
+ default:
92
+ return value;
93
+ }
94
+
95
+ };
96
+ if (dictionary.runs instanceof Array){
97
+ for (i = 0, l = dictionary.runs.length; i < l && maxLength > 0; ++i){
98
+ runDictionary = dictionary.runs[i];
99
+ attributes = {};
100
+ length = typeof(runDictionary.length) === "number" ? Math.min(maxLength, Math.floor(runDictionary.length)) : 0;
101
+ if (length > 0 && typeof(runDictionary.attributes) === "object"){
102
+ for (name in runDictionary.attributes){
103
+ attributes[name] = decodeAttribute(name, runDictionary.attributes[name]);
104
+ }
105
+ this._runs.push(JSAttributedStringRun(JSRange(location, length), attributes));
106
+ }
107
+ location += length;
108
+ maxLength -= length;
109
+ }
110
+ }
111
+ if (maxLength > 0){
112
+ this._runs.push(JSAttributedStringRun(JSRange(location, maxLength), {}));
113
+ }
114
+ if (this._runs.length === 0){
115
+ this._runs.push(JSAttributedStringRun(JSRange(0, 0), {}));
116
+ }
117
+ },
118
+
119
+ dictionaryRepresentation: function(){
120
+ var dictionary = {
121
+ string: this._string,
122
+ runs: []
123
+ };
124
+ var i, l;
125
+ var run;
126
+ var name;
127
+ var runDictionary;
128
+ var encodeAttribute = function(name, value){
129
+ switch (name){
130
+ case JSAttributedString.Attribute.font:
131
+ return JSAttributedString.AttributeEncoder.font(value);
132
+ case JSAttributedString.Attribute.textColor:
133
+ case JSAttributedString.Attribute.backgroundColor:
134
+ return JSAttributedString.AttributeEncoder.color(value);
135
+ case JSAttributedString.Attribute.link:
136
+ return JSAttributedString.AttributeEncoder.url(value);
137
+ case JSAttributedString.Attribute.cursor:
138
+ return JSAttributedString.Attribute.Encoder.skip(value);
139
+ case JSAttributedString.Attribute.attachment:
140
+ // TODO:
141
+ return JSAttributedString.Attribute.Encoder.skip(value);
142
+ case JSAttributedString.Attribute.bold:
143
+ case JSAttributedString.Attribute.italic:
144
+ case JSAttributedString.Attribute.underline:
145
+ case JSAttributedString.Attribute.strike:
146
+ case JSAttributedString.Attribute.lineHeightMultiple:
147
+ case JSAttributedString.Attribute.minimumLineHeight:
148
+ case JSAttributedString.Attribute.lineSpacing:
149
+ case JSAttributedString.Attribute.paragraphSpacing:
150
+ case JSAttributedString.Attribute.beforeParagraphSpacing:
151
+ case JSAttributedString.Attribute.firstLineHeadIndent:
152
+ case JSAttributedString.Attribute.headIndent:
153
+ case JSAttributedString.Attribute.tailIndent:
154
+ case JSAttributedString.Attribute.textAlignment:
155
+ case JSAttributedString.Attribute.lineBreakMode:
156
+ case JSAttributedString.Attribute.maskCharacter:
157
+ case JSAttributedString.Attribute.paragraphStyleName:
158
+ default:
159
+ return value;
160
+ }
161
+ };
162
+ for (i = 0, l = this._runs.length; i < l; ++i){
163
+ run = this._runs[i];
164
+ runDictionary = {
165
+ length: run.range.length,
166
+ attributes: {}
167
+ };
168
+ for (name in run.attributes){
169
+ runDictionary.attributes[name] = encodeAttribute(name, run.attributes[name]);
170
+ }
171
+ dictionary.runs.push(runDictionary);
172
+ }
173
+ return dictionary;
174
+ },
175
+
43
176
  initWithAttributedString: function(attributedString, defaultAttributes){
44
177
  this._string = attributedString.string;
45
178
  this._runs = [];
@@ -213,6 +346,8 @@ JSClass("JSAttributedString", JSObject, {
213
346
  }
214
347
  this._fixRunsAtIndex(runIndex);
215
348
  this._fixRunsAtIndex(runRange.location);
349
+ this._fixParagraphAttributesAtIndex(range.location);
350
+ this._fixParagraphAttributesAtIndex(range.location + attributedString.string.length);
216
351
  },
217
352
 
218
353
  // MARK: - Attribute mutations
@@ -402,6 +537,44 @@ JSClass("JSAttributedString", JSObject, {
402
537
  }
403
538
  },
404
539
 
540
+ _fixParagraphAttributesAtIndex: function(index){
541
+ if (index >= this._string.length){
542
+ return;
543
+ }
544
+ var paragraphRange = this._string.rangeForParagraphAtIndex(index);
545
+ var runIndex = this._runIndexForStringIndex(paragraphRange.location);
546
+ var run = this._runs[runIndex];
547
+ var paragraphAttributes = run.attributes;
548
+ var copy;
549
+ var i, l;
550
+ var attribute;
551
+ var value;
552
+ while (run.range.end < paragraphRange.end && runIndex < this._runs.length){
553
+ run = this._runs[runIndex];
554
+ if (!run.containsEqualParagraphAttributes(paragraphAttributes)){
555
+ if (run.range.end > paragraphRange.end){
556
+ copy = JSAttributedStringRun(JSRange(paragraphRange.end, run.range.end - paragraphRange.end), run.attributes);
557
+ this._runs.splice(runIndex + 1, 0, copy);
558
+ run.range.length -= copy.range.length;
559
+ }
560
+ for (i = 0, l = JSAttributedString.paragraphAttributes.length; i < l; ++i){
561
+ attribute = JSAttributedString.paragraphAttributes[i];
562
+ if (attribute in paragraphAttributes){
563
+ run.attributes[attribute] = paragraphAttributes[attribute];
564
+ }else{
565
+ delete run.attributes[attribute];
566
+ }
567
+ }
568
+ if (this._runs[runIndex - 1].onlyContainsEqualAttributes(run.attributes)){
569
+ this._runs[runIndex - 1].range.length += run.range.length;
570
+ this._runs.splice(runIndex, 1);
571
+ --runIndex;
572
+ }
573
+ }
574
+ ++runIndex;
575
+ }
576
+ },
577
+
405
578
  _rangeOfRunsPreparedForChangeInStringRange: function(range){
406
579
  var firstRunIndex = this._splitRunAtIndex(range.location);
407
580
  if (range.length > 0){
@@ -472,13 +645,84 @@ JSAttributedString.Attribute = {
472
645
  underline: "underline",
473
646
  strike: "strike",
474
647
  attachment: "attachment",
475
- lineHeight: "lineHeight",
476
- lineSpacing: "lineSpacing",
477
- textAlignment: "textAlignment",
478
- lineBreakMode: "lineBreakMode",
479
648
  maskCharacter: "maskCharacter",
480
649
  cursor: "cursor",
481
- link: "link"
650
+ link: "link",
651
+
652
+ // Paragraph
653
+ paragraphStyleName: "paragraphStyleName",
654
+ textAlignment: "textAlignment",
655
+ lineBreakMode: "lineBreakMode",
656
+ minimumLineHeight: "minimumLineHeight",
657
+ lineHeightMultiple: "lineHeightMultiple",
658
+ lineSpacing: "lineSpacing",
659
+ paragraphSpacing: "paragraphSpacing",
660
+ beforeParagraphSpacing: "beforeParagraphSpacing",
661
+ firstLineHeadIndent: "firstLineHeadIndent",
662
+ headIndent: "headIndent",
663
+ tailIndent: "tailIndent",
664
+ };
665
+
666
+ JSAttributedString.paragraphAttributes = [
667
+ JSAttributedString.Attribute.paragraphStyleName,
668
+ JSAttributedString.Attribute.textAlignment,
669
+ JSAttributedString.Attribute.lineBreakMode,
670
+ JSAttributedString.Attribute.minimumLineHeight,
671
+ JSAttributedString.Attribute.lineHeightMultiple,
672
+ JSAttributedString.Attribute.lineSpacing,
673
+ JSAttributedString.Attribute.paragraphSpacing,
674
+ JSAttributedString.Attribute.beforeParagraphSpacing,
675
+ JSAttributedString.Attribute.firstLineHeadIndent,
676
+ JSAttributedString.Attribute.headIndent,
677
+ JSAttributedString.Attribute.tailIndent
678
+ ];
679
+
680
+ JSAttributedString.AttributeEncoder = {
681
+ skip: function(value){ return undefined; },
682
+ identity: function(value){ return value; },
683
+ dataBase64: function(value){ return value.base64StringRepresentation(); },
684
+ dataBase64URL: function(value){ return value.base64URLStringRepresentation(); },
685
+ dataHex: function(value){ return value.hexStringRepresentation(); },
686
+ url: function(value){ return value.encodedString; },
687
+ font: function(value){ return value.dictionaryRepresentation(); },
688
+ color: function(value){ return value.dictionaryRepresentation(); },
689
+ enumName: function(obj){
690
+ return function(value){
691
+ for (var name in obj){
692
+ if (obj[name] === value){
693
+ return name;
694
+ }
695
+ }
696
+ };
697
+ }
698
+ };
699
+
700
+ JSAttributedString.AttributeDecoder = {
701
+ skip: function(value){ return undefined; },
702
+ identity: function(value){ return value; },
703
+ dataBase64: function(value){ return value.dataByDecodingBase64(); },
704
+ dataBase64URL: function(value){ return value.dataByDecodingBase64URL(); },
705
+ dataHex: function(value){ return value.dataByDecodingHex(); },
706
+ url: function(value){ return JSURL.initWithString(value); },
707
+ font: function(value){ return JSFont.initFromDictionary(value); },
708
+ color: function(value){ return JSColor.initFromDictionary(value); },
709
+ boolean: function(value){ return typeof(value) === "boolean" ? value : undefined; },
710
+ number: function(value){ return typeof(value) === "number" ? value : undefined; },
711
+ string: function(value){ return typeof(value) === "string" ? value : undefined; },
712
+ enumName: function(obj){
713
+ return function(value){
714
+ return obj[value];
715
+ };
716
+ },
717
+ enumValue: function(obj){
718
+ return function(value){
719
+ for (var name in obj){
720
+ if (obj[name] === value){
721
+ return value;
722
+ }
723
+ }
724
+ };
725
+ }
482
726
  };
483
727
 
484
728
  JSAttributedString.SpecialCharacter = {
@@ -550,6 +794,35 @@ JSAttributedStringRun.prototype = {
550
794
  return true;
551
795
  },
552
796
 
797
+ containsEqualParagraphAttributes: function(attributes){
798
+ var attribute;
799
+ var a, b;
800
+ for (var i = 0, l = JSAttributedString.paragraphAttributes.length; i < l; ++i){
801
+ attribute = JSAttributedString.paragraphAttributes[i];
802
+ a = attributes[attribute];
803
+ b = this.attributes[attribute];
804
+ if (a === undefined){
805
+ if (!!b){
806
+ return false;
807
+ }
808
+ }else if (a === null){
809
+ if (b !== null && b !== undefined){
810
+ return false;
811
+ }
812
+ }else if (a.isEqual){
813
+ if (b === null || b === undefined){
814
+ return false;
815
+ }
816
+ if (!a.isEqual(b)){
817
+ return false;
818
+ }
819
+ }else if (a != b){
820
+ return false;
821
+ }
822
+ }
823
+ return true;
824
+ }
825
+
553
826
  };
554
827
 
555
828
  var JSAttributedStringRunIterator = function(attributedString, startIndex){
@@ -620,7 +893,7 @@ Object.defineProperties(JSAttributedStringRunIterator.prototype, {
620
893
  return null;
621
894
  }
622
895
  var run = this._attributedString._runs[this._runIndex];
623
- if (run.range.length === 1 && this._attributedString.charCodeAt(run.range.location) === JSAttributedString.SpecialCharacter.attachment){
896
+ if (run.range.length === 1 && this._attributedString.string.charCodeAt(run.range.location) === JSAttributedString.SpecialCharacter.attachment){
624
897
  return run.attributes[JSAttributedString.Attribute.attachment];
625
898
  }
626
899
  return null;
@@ -157,8 +157,8 @@ JSClass("JSNodeFileManager", JSFileManager, {
157
157
  if (!error){
158
158
  attrs = {
159
159
  itemType: JSFileManager.ItemType.fromStat(stats),
160
- created: Math.floor(stats.ctimeMs),
161
- modified: Math.floor(stats.mtimeMs),
160
+ created: Math.floor(stats.ctimeMs / 1000.0),
161
+ updated: Math.floor(stats.mtimeMs / 1000.0),
162
162
  size: stats.size
163
163
  };
164
164
  }
@@ -49,7 +49,7 @@ JSClass("JSFont", JSObject, {
49
49
  var weight;
50
50
  var style;
51
51
  var size;
52
- var defaults = JSFont._systemFontDescriptor;
52
+ var defaults = JSFontDescriptor.system;
53
53
  // if ('descriptor' in values){
54
54
  // values = values.descriptor;
55
55
  // }
@@ -78,7 +78,7 @@ JSClass("JSFont", JSObject, {
78
78
  size = JSFont.Size.normal;
79
79
  }
80
80
  if (family){
81
- var descriptor = JSResourceFontDescriptor.descriptorWithFamily(family, weight, style);
81
+ var descriptor = JSFontDescriptor.descriptorWithFamily(family, weight, style);
82
82
  if (descriptor !== null){
83
83
  return JSFont.initWithDescriptor(descriptor, size);
84
84
  }
@@ -86,6 +86,30 @@ JSClass("JSFont", JSObject, {
86
86
  return null;
87
87
  },
88
88
 
89
+ initFromDictionary: function(dictionary){
90
+ var descriptor = JSFontDescriptor.descriptorWithFamily(dictionary.family, dictionary.weight, dictionary.style);
91
+ if (descriptor === null){
92
+ if (dictionary.url){
93
+ descriptor = JSURLFontDescriptor.initWithURL(JSURL.initWithString(dictionary.url), dictionary.family, dictionary.weight, dictionary.style);
94
+ JSFontDescriptor.registerDescriptor(descriptor);
95
+ }
96
+ }
97
+ if (descriptor !== null){
98
+ return JSFont.initWithDescriptor(descriptor, dictionary.size);
99
+ }
100
+ return null;
101
+ },
102
+
103
+ dictionaryRepresentation: function(){
104
+ return {
105
+ url: this.descriptor instanceof JSURLFontDescriptor ? this._descriptor.url : undefined,
106
+ family: this._descriptor.family,
107
+ weight: this._descriptor.weight,
108
+ style: this._descriptor.style,
109
+ size: this.pointSize
110
+ };
111
+ },
112
+
89
113
  getFullName: function(){
90
114
  return this._descriptor.name;
91
115
  },
@@ -187,7 +211,7 @@ JSClass("JSFont", JSObject, {
187
211
  });
188
212
 
189
213
  JSFont.fontWithFamily = function(family, pointSize, weight, style){
190
- var descriptor = JSResourceFontDescriptor.descriptorWithFamily(family, weight || JSFont.Weight.regular, style || JSFont.Style.normal);
214
+ var descriptor = JSFontDescriptor.descriptorWithFamily(family, weight || JSFont.Weight.regular, style || JSFont.Style.normal);
191
215
  return JSFont.initWithDescriptor(descriptor, pointSize);
192
216
  };
193
217
 
@@ -204,12 +228,12 @@ JSFont.registerBundleFonts = function(bundle){
204
228
 
205
229
  JSFont._registerFontResource = function(bundle, metadata){
206
230
  var descriptor = JSResourceFontDescriptor.initWithMetadata(bundle, metadata);
231
+ JSFontDescriptor.registerDescriptor(descriptor);
207
232
  return descriptor;
208
233
  };
209
234
 
210
- JSFont._systemFontDescriptor = null;
211
-
212
- JSFont.registerSystemFontResource = function(name){
235
+ JSFont.registerSystemFontResource = function(name, bundle){
236
+ bundle = bundle || JSBundle.mainBundle;
213
237
  var ext;
214
238
  var extIndex = name.lastIndexOf('.');
215
239
  var i, l;
@@ -221,33 +245,33 @@ JSFont.registerSystemFontResource = function(name){
221
245
  extGuessed = true;
222
246
  ext = "ttf";
223
247
  }
224
- var metadata = JSBundle.mainBundle.metadataForResourceName(name, ext);
248
+ var metadata = bundle.metadataForResourceName(name, ext);
225
249
  if (extGuessed && metadata === null){
226
250
  ext = "otf";
227
- metadata = JSBundle.mainBundle.metadataForResourceName(name, ext);
251
+ metadata = bundle.metadataForResourceName(name, ext);
228
252
  }
229
- this._systemFontDescriptor = JSResourceFontDescriptor.descriptorsByName[metadata.font.unique_identifier];
253
+ JSFontDescriptor.system = JSResourceFontDescriptor.descriptorsByName[metadata.font.unique_identifier];
230
254
  };
231
255
 
232
256
  JSFont.registerSystemFont = function(familyName, weight, style){
233
- this._systemFontDescriptor = JSResourceFontDescriptor.descriptorWithFamily(familyName, weight || JSFont.Weight.regular, style || JSFont.Style.normal);
257
+ JSFontDescriptor.system = JSFontDescriptor.descriptorWithFamily(familyName, weight || JSFont.Weight.regular, style || JSFont.Style.normal);
234
258
  };
235
259
 
236
260
  JSFont.registerSystemFontDescriptor = function(descriptor){
237
- this._systemFontDescriptor = descriptor;
261
+ JSFontDescriptor.system = descriptor;
238
262
  };
239
263
 
240
264
  JSFont.unregisterAllFonts = function(){
241
- JSResourceFontDescriptor.descriptorsByFamily = {};
265
+ JSFontDescriptor.descriptorsByFamily = {};
242
266
  JSResourceFontDescriptor.descriptorsByName = {};
243
- this._systemFontDescriptor = null;
267
+ JSFontDescriptor.system = null;
244
268
  };
245
269
 
246
270
  JSFont.systemFontOfSize = function(pointSize){
247
- if (this._systemFontDescriptor === null){
271
+ if (JSFontDescriptor.system === null){
248
272
  return null;
249
273
  }
250
- return JSFont.initWithDescriptor(this._systemFontDescriptor, pointSize);
274
+ return JSFont.initWithDescriptor(JSFontDescriptor.system, pointSize);
251
275
  };
252
276
 
253
277
  JSFont.Size = {
@@ -94,4 +94,12 @@ JSDataFontDescriptor.definePropertiesFromExtensions({
94
94
 
95
95
  });
96
96
 
97
+ JSURLFontDescriptor.definePropertiesFromExtensions({
98
+
99
+ htmlURLString: function(){
100
+ return this.url.encodedString;
101
+ }
102
+
103
+ });
104
+
97
105
  })();
@@ -18,6 +18,8 @@
18
18
  // #import "UnicodeChar.js"
19
19
  // #import "Zlib.js"
20
20
  // #import "CoreTypes.js"
21
+ // #import "JSURLSession.js"
22
+ /* global JSFont */
21
23
  'use strict';
22
24
 
23
25
  (function(){
@@ -38,11 +40,11 @@ JSClass("JSFontDescriptor", JSObject, {
38
40
  unitsPerEM: JSReadOnlyProperty('_unitsPerEM', 0),
39
41
 
40
42
  descriptorWithWeight: function(weight){
41
- return this;
43
+ return JSFontDescriptor.descriptorWithFamily(this.family, weight, this.style) || this;
42
44
  },
43
45
 
44
46
  descriptorWithStyle: function(style){
45
- return this;
47
+ return JSFontDescriptor.descriptorWithFamily(this.family, this.weight, style) || this;
46
48
  },
47
49
 
48
50
  glyphForCharacter: function(character){
@@ -89,6 +91,29 @@ JSClass("JSFontDescriptor", JSObject, {
89
91
 
90
92
  });
91
93
 
94
+ JSFontDescriptor.system = null;
95
+
96
+ JSFontDescriptor.descriptorsByFamily = {
97
+ };
98
+
99
+ JSFontDescriptor.registerDescriptor = function(descriptor){
100
+ if (!(descriptor._family in JSFontDescriptor.descriptorsByFamily)){
101
+ JSFontDescriptor.descriptorsByFamily[descriptor._family] = {};
102
+ }
103
+ if (!(descriptor._weight in JSFontDescriptor.descriptorsByFamily[descriptor._family])){
104
+ JSFontDescriptor.descriptorsByFamily[descriptor._family][descriptor._weight] = {};
105
+ }
106
+ if (!(descriptor._style in JSFontDescriptor.descriptorsByFamily[descriptor._family][descriptor._weight])){
107
+ JSFontDescriptor.descriptorsByFamily[descriptor._family][descriptor._weight][descriptor._style] = descriptor;
108
+ }
109
+ };
110
+
111
+ JSFontDescriptor.descriptorWithFamily = function(family, weight, style){
112
+ var weights = JSFontDescriptor.descriptorsByFamily[family] || {};
113
+ var styles = weights[weight] || {};
114
+ return styles[style] || null;
115
+ };
116
+
92
117
  JSClass("JSDataFontDescriptor", JSFontDescriptor, {
93
118
 
94
119
  data: null,
@@ -131,23 +156,6 @@ JSClass("JSResourceFontDescriptor", JSFontDescriptor, {
131
156
  widths: null,
132
157
  };
133
158
  JSResourceFontDescriptor.descriptorsByName[metadata.font.unique_identifier] = this;
134
- if (!(this._family in JSResourceFontDescriptor.descriptorsByFamily)){
135
- JSResourceFontDescriptor.descriptorsByFamily[this._family] = {};
136
- }
137
- if (!(this._weight in JSResourceFontDescriptor.descriptorsByFamily[this._family])){
138
- JSResourceFontDescriptor.descriptorsByFamily[this._family][this._weight] = {};
139
- }
140
- if (!(this._style in JSResourceFontDescriptor.descriptorsByFamily[this._family][this._weight])){
141
- JSResourceFontDescriptor.descriptorsByFamily[this._family][this._weight][this._style] = this;
142
- }
143
- },
144
-
145
- descriptorWithWeight: function(weight){
146
- return JSResourceFontDescriptor.descriptorWithFamily(this.family, weight, this.style) || this;
147
- },
148
-
149
- descriptorWithStyle: function(style){
150
- return JSResourceFontDescriptor.descriptorWithFamily(this.family, this.weight, style) || this;
151
159
  },
152
160
 
153
161
  glyphForCharacter: function(character){
@@ -228,17 +236,87 @@ JSClass("JSResourceFontDescriptor", JSFontDescriptor, {
228
236
 
229
237
  });
230
238
 
231
- JSResourceFontDescriptor.descriptorWithFamily = function(family, weight, style){
232
- var weights = JSResourceFontDescriptor.descriptorsByFamily[family] || {};
233
- var styles = weights[weight] || {};
234
- return styles[style];
239
+ JSResourceFontDescriptor.descriptorsByName = {
235
240
  };
236
241
 
237
- JSResourceFontDescriptor.descriptorsByFamily = {
238
- };
242
+ JSClass("JSURLFontDescriptor", JSFontDescriptor, {
239
243
 
240
- JSResourceFontDescriptor.descriptorsByName = {
241
- };
244
+ url: null,
245
+
246
+ initWithURL: function(url, family, weight, style){
247
+ this.url = url;
248
+ this._family = family;
249
+ this._weight = weight;
250
+ this._style = style;
251
+ this._postScriptName = "%s-%s".sprintf(family.replace(" ", ""), this.face.replce(" ", ""));
252
+ // this._ascender
253
+ // this._descender
254
+ // this._unitsPerEM
255
+ },
256
+
257
+ getData: function(completion, target){
258
+ if (!completion){
259
+ completion = Promise.completion(Promise.rejectNonNullSecondArgument);
260
+ }
261
+ var session = JSURLSession.shared;
262
+ var task = session.dataTaskWithURL(this.url, function(error){
263
+ if (error !== null){
264
+ completion.call(target, null, error);
265
+ return;
266
+ }
267
+ try{
268
+ task.response.assertSuccess();
269
+ }catch (e){
270
+ completion.call(target, null, e);
271
+ return;
272
+ }
273
+ completion.call(target, task.response.data, null);
274
+ });
275
+ task.resume();
276
+ return completion.promise;
277
+ },
278
+
279
+ face: JSLazyInitProperty(function(){
280
+ if (this.weight === JSFont.Weight.regular){
281
+ if (this.style === JSFont.Style.italic){
282
+ return "Italic";
283
+ }
284
+ return "Regular";
285
+ }
286
+ var name = "";
287
+ switch (this.weight){
288
+ case JSFont.Weight.ultraLight:
289
+ name = "UltraLight";
290
+ break;
291
+ case JSFont.Weight.thin:
292
+ name = "Thin";
293
+ break;
294
+ case JSFont.Weight.light:
295
+ name = "Light";
296
+ break;
297
+ case JSFont.Weight.medium:
298
+ name = "Medium";
299
+ break;
300
+ case JSFont.Weight.semibold:
301
+ name = "SemiBold";
302
+ break;
303
+ case JSFont.Weight.bold:
304
+ name = "Bold";
305
+ break;
306
+ case JSFont.Weight.heavy:
307
+ name = "Heavy";
308
+ break;
309
+ case JSFont.Weight.black:
310
+ name = "Black";
311
+ break;
312
+ }
313
+ if (this.style === JSFont.Style.italic){
314
+ name += " Italic";
315
+ }
316
+ return name;
317
+ }),
318
+
319
+ });
242
320
 
243
321
  var CMap = function(format, data){
244
322
  if (this === undefined){