@breakside/jskit 2026.11.0 → 2026.26.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.
- package/Frameworks/DOM.jsframework/Info.json +2 -2
- package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
- package/Frameworks/FontKit.jsframework/Info.json +2 -2
- package/Frameworks/FontKit.jsframework/JS/FNTOpenTypeFont.js +331 -22
- package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
- package/Frameworks/Foundation.jsframework/Info.json +2 -2
- package/Frameworks/Foundation.jsframework/JS/JSAttributedString.js +13 -1
- package/Frameworks/Foundation.jsframework/JS/JSContext.js +44 -17
- package/Frameworks/Foundation.jsframework/JS/JSCubicBezier.js +54 -1
- package/Frameworks/Foundation.jsframework/JS/JSFont.js +8 -9
- package/Frameworks/Foundation.jsframework/JS/JSGradient.js +28 -2
- package/Frameworks/Foundation.jsframework/JS/JSImage+HTML.js +27 -1
- package/Frameworks/Foundation.jsframework/JS/JSNumberFormatter.js +23 -1
- package/Frameworks/Foundation.jsframework/JS/JSPath.js +192 -6
- package/Frameworks/Foundation.jsframework/JS/JSPoint.js +56 -0
- package/Frameworks/Foundation.jsframework/JS/JSTextRun.js +21 -4
- package/Frameworks/Foundation.jsframework/JS/JSTextStorage.js +5 -0
- package/Frameworks/Foundation.jsframework/JS/JSTextTypesetter.js +6 -1
- package/Frameworks/Foundation.jsframework/JS/JSXMLParser.js +1 -1
- package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
- package/Frameworks/Foundation.jsframework/sources.json +1 -0
- package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
- package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
- package/Info.json +2 -2
- package/Node/io.breakside.jskit-bundle.js +2 -2
- package/Root/Frameworks/APIKit/Info.yaml +1 -1
- package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/AuthKit/Info.yaml +1 -1
- package/Root/Frameworks/CSSOM/Info.yaml +1 -1
- package/Root/Frameworks/ChartKit/Info.yaml +1 -1
- package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
- package/Root/Frameworks/DBKit/Info.yaml +1 -1
- package/Root/Frameworks/DOM/Info.yaml +1 -1
- package/Root/Frameworks/Dispatch/Info.yaml +1 -1
- package/Root/Frameworks/FontKit/FNTOpenTypeFont.js +331 -22
- package/Root/Frameworks/FontKit/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/JSAttributedString.js +13 -1
- package/Root/Frameworks/Foundation/JSContext.js +44 -17
- package/Root/Frameworks/Foundation/JSCubicBezier.js +54 -1
- package/Root/Frameworks/Foundation/JSFont.js +8 -9
- package/Root/Frameworks/Foundation/JSGradient.js +28 -2
- package/Root/Frameworks/Foundation/JSImage+HTML.js +27 -1
- package/Root/Frameworks/Foundation/JSNumberFormatter.js +23 -1
- package/Root/Frameworks/Foundation/JSPath.js +192 -6
- package/Root/Frameworks/Foundation/JSPoint.js +56 -0
- package/Root/Frameworks/Foundation/JSTextRun.js +21 -4
- package/Root/Frameworks/Foundation/JSTextStorage.js +5 -0
- package/Root/Frameworks/Foundation/JSTextTypesetter.js +6 -1
- package/Root/Frameworks/Foundation/JSXMLParser.js +1 -1
- package/Root/Frameworks/ImageKit/IKHTMLCanvasBitmapContext.js +187 -101
- package/Root/Frameworks/ImageKit/IKNodeBitmapContext.js +4 -4
- package/Root/Frameworks/ImageKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
- package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
- package/Root/Frameworks/PDFKit/Info.yaml +1 -1
- package/Root/Frameworks/QRKit/Info.yaml +1 -1
- package/Root/Frameworks/SearchKit/Info.yaml +1 -1
- package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/TestKit/Info.yaml +1 -1
- package/Root/Frameworks/TestKit/TKAssert.js +4 -4
- package/Root/Frameworks/UIKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/UIApplication.js +9 -1
- package/Root/Frameworks/UIKit/UICollectionView.js +4 -0
- package/Root/Frameworks/UIKit/UIColorPanel.js +46 -0
- package/Root/Frameworks/UIKit/UIColorWell.js +8 -0
- package/Root/Frameworks/UIKit/UIHTMLDisplayServer.js +21 -2
- package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +150 -69
- package/Root/Frameworks/UIKit/UIHTMLTextRun.js +5 -0
- package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +18 -3
- package/Root/Frameworks/UIKit/UIListView.js +7 -5
- package/Root/Frameworks/UIKit/UIMenu.js +50 -32
- package/Root/Frameworks/UIKit/UIMenuItem.js +12 -0
- package/Root/Frameworks/UIKit/UIMenuView.js +27 -5
- package/Root/Frameworks/UIKit/UIPlatform.js +7 -0
- package/Root/Frameworks/UIKit/UIPopupButton.js +7 -1
- package/Root/Frameworks/UIKit/UIResponder.js +8 -0
- package/Root/Frameworks/UIKit/UITextEditor.js +14 -7
- package/Root/Frameworks/UIKit/UITokenField.js +65 -0
- package/Root/Frameworks/UIKit/UIToolbar.js +1 -1
- package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
- package/package.json +1 -1
|
@@ -145,28 +145,28 @@ JSGlobalObject.TKAssertExactEquals = function(a, b, message){
|
|
|
145
145
|
JSGlobalObject.TKAssertLessThan = function(a, b, message){
|
|
146
146
|
if (a >= b){
|
|
147
147
|
message = message || '';
|
|
148
|
-
throw TKAssertion('
|
|
148
|
+
throw TKAssertion('TKAssertLessThan failed, ' + (a) + ' >= ' + (b) + '. ' + (message || ''));
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
JSGlobalObject.TKAssertGreaterThan = function(a, b, message){
|
|
153
153
|
if (a <= b){
|
|
154
154
|
message = message || '';
|
|
155
|
-
throw TKAssertion('
|
|
155
|
+
throw TKAssertion('TKAssertGreaterThan failed, ' + (a) + ' <= ' + (b) + '. ' + (message || ''));
|
|
156
156
|
}
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
JSGlobalObject.TKAssertLessThanOrEquals = function(a, b, message){
|
|
160
160
|
if (a > b){
|
|
161
161
|
message = message || '';
|
|
162
|
-
throw TKAssertion('
|
|
162
|
+
throw TKAssertion('TKAssertLessThanOrEquals failed, ' + (a) + ' > ' + (b) + '. ' + (message || ''));
|
|
163
163
|
}
|
|
164
164
|
};
|
|
165
165
|
|
|
166
166
|
JSGlobalObject.TKAssertGreaterThanOrEquals = function(a, b, message){
|
|
167
167
|
if (a < b){
|
|
168
168
|
message = message || '';
|
|
169
|
-
throw TKAssertion('
|
|
169
|
+
throw TKAssertion('TKAssertGreaterThanOrEquals failed, ' + (a) + ' < ' + (b) + '. ' + (message || ''));
|
|
170
170
|
}
|
|
171
171
|
};
|
|
172
172
|
|
|
@@ -372,7 +372,7 @@ JSClass('UIApplication', UIResponder, {
|
|
|
372
372
|
// MARK: - Sending Events & Actions
|
|
373
373
|
|
|
374
374
|
sendEvent: function(event){
|
|
375
|
-
if (event.category === UIEvent.Category.key && event.type === UIEvent.Type.keyDown && UIPlatform.shared && event.hasModifier(UIPlatform.shared.commandModifier)){
|
|
375
|
+
if (event.category === UIEvent.Category.key && event.type === UIEvent.Type.keyDown && UIPlatform.shared && event.hasModifier(UIPlatform.shared.commandModifier) && event.key !== UIPlatform.shared.commandKey){
|
|
376
376
|
var mainMenu = this.mainMenu;
|
|
377
377
|
if (mainMenu){
|
|
378
378
|
if (mainMenu.performKeyEquivalent(event)){
|
|
@@ -384,6 +384,14 @@ JSClass('UIApplication', UIResponder, {
|
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
|
+
if (this.keyWindow !== null && this.keyWindow.firstResponder !== null){
|
|
388
|
+
var shortcutMenu = this.keyWindow.firstResponder.getShortcutMenu();
|
|
389
|
+
if (shortcutMenu !== null){
|
|
390
|
+
if (shortcutMenu.performKeyEquivalent(event)){
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
387
395
|
}
|
|
388
396
|
if (event.category === UIEvent.Category.touches){
|
|
389
397
|
var sentWindowIds = new Set();
|
|
@@ -1454,6 +1454,10 @@ JSClass("UICollectionView", UIScrollView, {
|
|
|
1454
1454
|
if (this.delegate && this.delegate.collectionViewWillBeginDraggingSession){
|
|
1455
1455
|
this.delegate.collectionViewWillBeginDraggingSession(this, session, indexPaths, location);
|
|
1456
1456
|
}
|
|
1457
|
+
if (cell.over){
|
|
1458
|
+
cell.over = false;
|
|
1459
|
+
}
|
|
1460
|
+
cell.active = false;
|
|
1457
1461
|
}
|
|
1458
1462
|
}else{
|
|
1459
1463
|
// TODO: scrolling (see UITextEditor for similar use case)
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
|
|
22
22
|
JSProtocol("UIColorPanelDelegate", JSProtocol, {
|
|
23
23
|
|
|
24
|
+
colorPanelDidBeginEditing: function(panel, event){},
|
|
25
|
+
colorPanelDidEndEditing: function(panel, event){},
|
|
24
26
|
colorPanelDidChangeColor: function(panel, color){},
|
|
25
27
|
colorPanelDidClose: function(panel){}
|
|
26
28
|
|
|
@@ -239,8 +241,14 @@ JSClass("UIColorPanelViewController", UIViewController, {
|
|
|
239
241
|
this.hexField.leftAccessoryVisibility = UITextField.AccessoryVisibility.always;
|
|
240
242
|
|
|
241
243
|
this.saturationBrightnessControl.addAction(this.saturationBrightnessChanged, this);
|
|
244
|
+
this.saturationBrightnessControl.addAction(this.saturationBrightnessEditingBegan, this, UIControl.Event.editingDidBegin);
|
|
245
|
+
this.saturationBrightnessControl.addAction(this.saturationBrightnessEditingEnded, this, UIControl.Event.editingDidEnd);
|
|
242
246
|
this.hueSlider.addAction(this.hueSliderChanged, this);
|
|
247
|
+
this.hueSlider.addAction(this.hueSliderEditingBegan, this, UIControl.Event.editingDidBegin);
|
|
248
|
+
this.hueSlider.addAction(this.hueSliderEditingEnded, this, UIControl.Event.editingDidEnd);
|
|
243
249
|
this.alphaSlider.addAction(this.alphaSliderChanged, this);
|
|
250
|
+
this.alphaSlider.addAction(this.alphaSliderEditingBegan, this, UIControl.Event.editingDidBegin);
|
|
251
|
+
this.alphaSlider.addAction(this.alphaSliderEditingEnded, this, UIControl.Event.editingDidEnd);
|
|
244
252
|
this.hexField.addAction(this.hexFieldChanged, this);
|
|
245
253
|
this.component1Field.addAction(this.component1FieldChanged, this);
|
|
246
254
|
this.component2Field.addAction(this.component2FieldChanged, this);
|
|
@@ -308,6 +316,18 @@ JSClass("UIColorPanelViewController", UIViewController, {
|
|
|
308
316
|
this.notifyDelegateOfColor();
|
|
309
317
|
},
|
|
310
318
|
|
|
319
|
+
saturationBrightnessEditingBegan: function(sender, event){
|
|
320
|
+
if (this.delegate && this.delegate.colorPanelDidBeginEditing){
|
|
321
|
+
this.delegate.colorPanelDidBeginEditing(this, event);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
saturationBrightnessEditingEnded: function(sender, event){
|
|
326
|
+
if (this.delegate && this.delegate.colorPanelDidEndEditing){
|
|
327
|
+
this.delegate.colorPanelDidEndEditing(this, event);
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
|
|
311
331
|
hueSliderChanged: function(slider){
|
|
312
332
|
this._hsvComponents[0] = slider.value;
|
|
313
333
|
this._recalculateColorFromHSV();
|
|
@@ -315,12 +335,36 @@ JSClass("UIColorPanelViewController", UIViewController, {
|
|
|
315
335
|
this.notifyDelegateOfColor();
|
|
316
336
|
},
|
|
317
337
|
|
|
338
|
+
hueSliderEditingBegan: function(sender, event){
|
|
339
|
+
if (this.delegate && this.delegate.colorPanelDidBeginEditing){
|
|
340
|
+
this.delegate.colorPanelDidBeginEditing(this, event);
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
hueSliderEditingEnded: function(sender, event){
|
|
345
|
+
if (this.delegate && this.delegate.colorPanelDidEndEditing){
|
|
346
|
+
this.delegate.colorPanelDidEndEditing(this, event);
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
|
|
318
350
|
alphaSliderChanged: function(slider){
|
|
319
351
|
this._color = this._color.colorWithAlpha(slider.value);
|
|
320
352
|
this._alphaChanged(slider);
|
|
321
353
|
this.notifyDelegateOfColor();
|
|
322
354
|
},
|
|
323
355
|
|
|
356
|
+
alphaSliderEditingBegan: function(sender, event){
|
|
357
|
+
if (this.delegate && this.delegate.colorPanelDidBeginEditing){
|
|
358
|
+
this.delegate.colorPanelDidBeginEditing(this, event);
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
alphaSliderEditingEnded: function(sender, event){
|
|
363
|
+
if (this.delegate && this.delegate.colorPanelDidEndEditing){
|
|
364
|
+
this.delegate.colorPanelDidEndEditing(this, event);
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
|
|
324
368
|
component1FieldChanged: function(textField){
|
|
325
369
|
var value = textField.integerValue;
|
|
326
370
|
if (isNaN(value)){
|
|
@@ -829,6 +873,7 @@ JSClass("UIColorPanelTwoAxisSlider", UIControl, {
|
|
|
829
873
|
initialOffset: JSPoint.Zero,
|
|
830
874
|
};
|
|
831
875
|
this.active = true;
|
|
876
|
+
this.sendActionsForEvents(UIControl.Event.editingDidBegin, event);
|
|
832
877
|
if (!isOnKnob){
|
|
833
878
|
this.value = this.valueForPoint(location);
|
|
834
879
|
this.didChangeValueForBinding('value');
|
|
@@ -852,6 +897,7 @@ JSClass("UIColorPanelTwoAxisSlider", UIControl, {
|
|
|
852
897
|
_endSlide: function(event){
|
|
853
898
|
if (this.active){
|
|
854
899
|
this.active = false;
|
|
900
|
+
this.sendActionsForEvents(UIControl.Event.editingDidEnd, event);
|
|
855
901
|
}
|
|
856
902
|
this._drag = null;
|
|
857
903
|
},
|
|
@@ -211,6 +211,14 @@ JSClass("UIColorWell", UIControl, {
|
|
|
211
211
|
// ----------------------------------------------------------------------
|
|
212
212
|
// MARK: - Color Panel
|
|
213
213
|
|
|
214
|
+
colorPanelDidBeginEditing: function(panel, event){
|
|
215
|
+
this.sendActionsForEvents(UIControl.Event.editingDidBegin, event);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
colorPanelDidEndEditing: function(panel, event){
|
|
219
|
+
this.sendActionsForEvents(UIControl.Event.editingDidEnd, event);
|
|
220
|
+
},
|
|
221
|
+
|
|
214
222
|
colorPanelDidChangeColor: function(panel, color){
|
|
215
223
|
this._changeColor(color);
|
|
216
224
|
},
|
|
@@ -419,12 +419,31 @@ JSClass("UIHTMLDisplayServer", UIDisplayServer, {
|
|
|
419
419
|
}
|
|
420
420
|
insertedLayersByParentContext[info.parentContext.objectID].push(info.layer);
|
|
421
421
|
}
|
|
422
|
+
var parentContext;
|
|
423
|
+
var context;
|
|
424
|
+
var i, l;
|
|
422
425
|
for (var contextId in insertedLayersByParentContext){
|
|
423
426
|
insertedLayersByParentContext[contextId].sort(function(a, b){
|
|
424
427
|
return a.sublayerIndex - b.sublayerIndex;
|
|
425
428
|
});
|
|
426
|
-
|
|
427
|
-
|
|
429
|
+
parentContext = parentContextsById[contextId];
|
|
430
|
+
// If a layer's element is already in the parent element (meaning it
|
|
431
|
+
// is just changing order), first remove it from the parent element
|
|
432
|
+
// so sublayer index calculations will work correctly.
|
|
433
|
+
// NOTE: UIHTMLDisplayServerCanvasContext.insertSublayerContext()
|
|
434
|
+
// already checked for this, but its check only worked when moving a
|
|
435
|
+
// single layer. When adding moving and adding multiple layers at
|
|
436
|
+
// a time, we need first to remove all elements that moving before
|
|
437
|
+
// trying to insert or re-insert any of moved/added elements.
|
|
438
|
+
for (i = 0, l = insertedLayersByParentContext[contextId].length; i < l; ++i){
|
|
439
|
+
layer = insertedLayersByParentContext[contextId][i];
|
|
440
|
+
context = this.contextsByObjectID[layer.objectID];
|
|
441
|
+
if (context && context.element.parentNode === parentContext.element){
|
|
442
|
+
parentContext.element.removeChild(context.element);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
for (i = 0, l = insertedLayersByParentContext[contextId].length; i < l; ++i){
|
|
446
|
+
this._insertLayerIntoDOM(insertedLayersByParentContext[contextId][i], parentContext);
|
|
428
447
|
}
|
|
429
448
|
}
|
|
430
449
|
this._insertedLayers = {};
|
|
@@ -578,6 +578,18 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
578
578
|
},
|
|
579
579
|
|
|
580
580
|
fillMaskedRect: function(rect, maskImage){
|
|
581
|
+
if (maskImage._htmlImage !== undefined && maskImage._htmlImage !== null){
|
|
582
|
+
var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
|
|
583
|
+
maskCanvas.width = rect.size.width;
|
|
584
|
+
maskCanvas.height = rect.size.height;
|
|
585
|
+
var maskContext = maskCanvas.getContext('2d');
|
|
586
|
+
maskContext.fillStyle = this.state.fillColor.cssString();
|
|
587
|
+
maskContext.fillRect(0, 0, rect.size.width, rect.size.height);
|
|
588
|
+
maskContext.globalCompositeOperation = 'destination-in';
|
|
589
|
+
maskContext.drawImage(maskImage._htmlImage, 0, 0, rect.size.width, rect.size.height);
|
|
590
|
+
this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
581
593
|
var imageElement = this._dequeueReusableImageElement();
|
|
582
594
|
this._positionImageElement(imageElement, maskImage, rect);
|
|
583
595
|
var url = maskImage.htmlURLString();
|
|
@@ -602,6 +614,10 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
602
614
|
_imageElementIndex: 0,
|
|
603
615
|
|
|
604
616
|
drawImage: function(image, rect){
|
|
617
|
+
if (image._htmlImage !== null && image._htmlImage !== undefined){
|
|
618
|
+
this.canvasContext.drawImage(image._htmlImage, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
605
621
|
if (image !== null){
|
|
606
622
|
var url = image.htmlURLString();
|
|
607
623
|
// FIXME: proof of concept, but really shouldn't do async
|
|
@@ -687,57 +703,96 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
687
703
|
|
|
688
704
|
drawLinearGradient: function(gradient, rect){
|
|
689
705
|
this.canvasContext.save();
|
|
690
|
-
var canvasGradient = this.canvasContext
|
|
691
|
-
rect.origin.x + gradient.start.x * rect.size.width,
|
|
692
|
-
rect.origin.y + gradient.start.y * rect.size.height,
|
|
693
|
-
rect.origin.x + gradient.end.x * rect.size.width,
|
|
694
|
-
rect.origin.y + gradient.end.y * rect.size.height
|
|
695
|
-
);
|
|
696
|
-
var stop;
|
|
697
|
-
for (var i = 0, l = gradient.stops.length; i < l; ++i){
|
|
698
|
-
stop = gradient.stops[i];
|
|
699
|
-
canvasGradient.addColorStop(stop.position, stop.color.cssString());
|
|
700
|
-
}
|
|
706
|
+
var canvasGradient = this._linearGradientForCanvasContext(this.canvasContext, gradient, rect);
|
|
701
707
|
this.canvasContext.fillStyle = canvasGradient;
|
|
702
708
|
this.canvasContext.fillRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
703
709
|
this.canvasContext.restore();
|
|
704
710
|
},
|
|
705
711
|
|
|
706
712
|
drawRadialGradient: function(gradient, rect){
|
|
707
|
-
var r0 = 0;
|
|
708
|
-
var start = JSPoint(
|
|
709
|
-
rect.origin.x + gradient.start.x * rect.size.width,
|
|
710
|
-
rect.origin.y + gradient.start.y * rect.size.height
|
|
711
|
-
);
|
|
712
|
-
var end = JSPoint(
|
|
713
|
-
rect.origin.x + gradient.end.x * rect.size.width,
|
|
714
|
-
rect.origin.y + gradient.end.y * rect.size.height
|
|
715
|
-
);
|
|
716
|
-
var r1 = start.distanceToPoint(end);
|
|
717
713
|
this.canvasContext.save();
|
|
718
|
-
var canvasGradient = this.canvasContext
|
|
719
|
-
start.x,
|
|
720
|
-
start.y,
|
|
721
|
-
r0,
|
|
722
|
-
start.x,
|
|
723
|
-
start.y,
|
|
724
|
-
r1
|
|
725
|
-
);
|
|
726
|
-
var stop;
|
|
727
|
-
for (var i = 0, l = gradient.stops.length; i < l; ++i){
|
|
728
|
-
stop = gradient.stops[i];
|
|
729
|
-
canvasGradient.addColorStop(stop.position, stop.color.cssString());
|
|
730
|
-
}
|
|
714
|
+
var canvasGradient = this._radialGradientForCanvasContext(this.canvasContext, gradient, rect);
|
|
731
715
|
this.canvasContext.fillStyle = canvasGradient;
|
|
732
716
|
this.canvasContext.fillRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
733
717
|
this.canvasContext.restore();
|
|
734
718
|
},
|
|
735
719
|
|
|
736
|
-
|
|
720
|
+
drawMaskedLinearGradient: function(gradient, rect, maskImage){
|
|
721
|
+
if (maskImage._htmlImage !== undefined && maskImage._htmlImage !== null){
|
|
722
|
+
var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
|
|
723
|
+
maskCanvas.width = rect.size.width;
|
|
724
|
+
maskCanvas.height = rect.size.height;
|
|
725
|
+
var maskContext = maskCanvas.getContext('2d');
|
|
726
|
+
var canvasGradient = this._linearGradientForCanvasContext(maskContext, gradient, JSRect(JSPoint.Zero, rect.size));
|
|
727
|
+
maskContext.fillStyle = canvasGradient;
|
|
728
|
+
maskContext.fillRect(0, 0, rect.size.width, rect.size.height);
|
|
729
|
+
maskContext.globalCompositeOperation = 'destination-in';
|
|
730
|
+
maskContext.drawImage(maskImage._htmlImage, 0, 0, rect.size.width, rect.size.height);
|
|
731
|
+
this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
var imageElement = this._dequeueReusableImageElement();
|
|
735
|
+
this._positionImageElement(imageElement, maskImage, rect);
|
|
736
|
+
var url = maskImage.htmlURLString();
|
|
737
|
+
var cssURL = "url('" + url + "')";
|
|
738
|
+
imageElement.style.maskImage = cssURL;
|
|
739
|
+
imageElement.style.maskSize = '100% 100%';
|
|
740
|
+
imageElement.style.webkitMaskImage = cssURL;
|
|
741
|
+
imageElement.style.webkitMaskSize = '100% 100%';
|
|
742
|
+
imageElement.style.backgroundImage = gradient.cssString(rect.size);
|
|
743
|
+
this._insertChildElement(imageElement);
|
|
744
|
+
},
|
|
745
|
+
|
|
746
|
+
drawMaskedRadialGradient: function(gradient, rect, maskImage){
|
|
747
|
+
if (maskImage._htmlImage !== undefined && maskImage._htmlImage !== null){
|
|
748
|
+
var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
|
|
749
|
+
maskCanvas.width = rect.size.width;
|
|
750
|
+
maskCanvas.height = rect.size.height;
|
|
751
|
+
var maskContext = maskCanvas.getContext('2d');
|
|
752
|
+
var canvasGradient = this._radialGradientForCanvasContext(maskContext, gradient, JSRect(JSPoint.Zero, rect.size));
|
|
753
|
+
maskContext.fillStyle = canvasGradient;
|
|
754
|
+
maskContext.fillRect(0, 0, rect.size.width, rect.size.height);
|
|
755
|
+
maskContext.globalCompositeOperation = 'destination-in';
|
|
756
|
+
maskContext.drawImage(maskImage._htmlImage, 0, 0, rect.size.width, rect.size.height);
|
|
757
|
+
this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
var imageElement = this._dequeueReusableImageElement();
|
|
761
|
+
this._positionImageElement(imageElement, maskImage, rect);
|
|
762
|
+
var url = maskImage.htmlURLString();
|
|
763
|
+
var cssURL = "url('" + url + "')";
|
|
764
|
+
imageElement.style.maskImage = cssURL;
|
|
765
|
+
imageElement.style.maskSize = '100% 100%';
|
|
766
|
+
imageElement.style.webkitMaskImage = cssURL;
|
|
767
|
+
imageElement.style.webkitMaskSize = '100% 100%';
|
|
768
|
+
imageElement.style.backgroundImage = gradient.radialCSSString(rect.size);
|
|
769
|
+
this._insertChildElement(imageElement);
|
|
770
|
+
},
|
|
771
|
+
|
|
772
|
+
drawLinearGradientStroke: function(gradient, path, alternateRect){
|
|
773
|
+
var rect = path.boundingRect;
|
|
774
|
+
this.canvasContext.save();
|
|
775
|
+
this.addPath(path);
|
|
776
|
+
var canvasGradient = this._linearGradientForCanvasContext(this.canvasContext, gradient, alternateRect || rect);
|
|
777
|
+
this.canvasContext.strokeStyle = canvasGradient;
|
|
778
|
+
this.canvasContext.stroke();
|
|
779
|
+
this.canvasContext.restore();
|
|
780
|
+
this.beginPath();
|
|
781
|
+
},
|
|
782
|
+
|
|
783
|
+
drawRadialGradientStroke: function(gradient, path, alternateRect){
|
|
737
784
|
var rect = path.boundingRect;
|
|
738
785
|
this.canvasContext.save();
|
|
739
786
|
this.addPath(path);
|
|
740
|
-
var canvasGradient = this.canvasContext
|
|
787
|
+
var canvasGradient = this._radialGradientForCanvasContext(this.canvasContext, gradient, alternateRect || rect);
|
|
788
|
+
this.canvasContext.strokeStyle = canvasGradient;
|
|
789
|
+
this.canvasContext.stroke();
|
|
790
|
+
this.canvasContext.restore();
|
|
791
|
+
this.beginPath();
|
|
792
|
+
},
|
|
793
|
+
|
|
794
|
+
_linearGradientForCanvasContext: function(canvasContext, gradient, rect){
|
|
795
|
+
var canvasGradient = canvasContext.createLinearGradient(
|
|
741
796
|
rect.origin.x + gradient.start.x * rect.size.width,
|
|
742
797
|
rect.origin.y + gradient.start.y * rect.size.height,
|
|
743
798
|
rect.origin.x + gradient.end.x * rect.size.width,
|
|
@@ -748,14 +803,10 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
748
803
|
stop = gradient.stops[i];
|
|
749
804
|
canvasGradient.addColorStop(stop.position, stop.color.cssString());
|
|
750
805
|
}
|
|
751
|
-
|
|
752
|
-
this.canvasContext.stroke();
|
|
753
|
-
this.canvasContext.restore();
|
|
754
|
-
this.beginPath();
|
|
806
|
+
return canvasGradient;
|
|
755
807
|
},
|
|
756
808
|
|
|
757
|
-
|
|
758
|
-
var rect = path.boundingRect;
|
|
809
|
+
_radialGradientForCanvasContext: function(canvasContext, gradient, rect){
|
|
759
810
|
var r0 = 0;
|
|
760
811
|
var start = JSPoint(
|
|
761
812
|
rect.origin.x + gradient.start.x * rect.size.width,
|
|
@@ -766,9 +817,7 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
766
817
|
rect.origin.y + gradient.end.y * rect.size.height
|
|
767
818
|
);
|
|
768
819
|
var r1 = start.distanceToPoint(end);
|
|
769
|
-
|
|
770
|
-
this.addPath(path);
|
|
771
|
-
var canvasGradient = this.canvasContext.createRadialGradient(
|
|
820
|
+
var canvasGradient = canvasContext.createRadialGradient(
|
|
772
821
|
start.x,
|
|
773
822
|
start.y,
|
|
774
823
|
r0,
|
|
@@ -781,10 +830,7 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
781
830
|
stop = gradient.stops[i];
|
|
782
831
|
canvasGradient.addColorStop(stop.position, stop.color.cssString());
|
|
783
832
|
}
|
|
784
|
-
|
|
785
|
-
this.canvasContext.stroke();
|
|
786
|
-
this.canvasContext.restore();
|
|
787
|
-
this.beginPath();
|
|
833
|
+
return canvasGradient;
|
|
788
834
|
},
|
|
789
835
|
|
|
790
836
|
// ----------------------------------------------------------------------
|
|
@@ -917,6 +963,45 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
|
|
|
917
963
|
}
|
|
918
964
|
},
|
|
919
965
|
|
|
966
|
+
// ----------------------------------------------------------------------
|
|
967
|
+
// MARK: - Transparency Layers
|
|
968
|
+
|
|
969
|
+
_reusableTransparencyLayer: null,
|
|
970
|
+
|
|
971
|
+
createTransparencyLayer: function(){
|
|
972
|
+
var scale = this.deviceScale * this.renderScale;
|
|
973
|
+
if (this._reusableTransparencyLayer !== null){
|
|
974
|
+
layer = this._reusableTransparencyLayer;
|
|
975
|
+
this._reusableTransparencyLayer = null;
|
|
976
|
+
layer.context.resetTransform();
|
|
977
|
+
layer.context.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
|
|
978
|
+
this._canvasContextAdoptState(layer.context, this.state, scale);
|
|
979
|
+
layer.parentContext = this.canvasContext;
|
|
980
|
+
this._canvasContext = layer.context;
|
|
981
|
+
return layer;
|
|
982
|
+
}
|
|
983
|
+
var parentContext = this.canvasContext;
|
|
984
|
+
var canvas = this._canvasElements[0].ownerDocument.createElement("canvas");
|
|
985
|
+
canvas.width = this._canvasElements[0].width;
|
|
986
|
+
canvas.height = this._canvasElements[0].height;
|
|
987
|
+
var context = canvas.getContext("2d");
|
|
988
|
+
this._canvasContextAdoptState(context, this.state, scale);
|
|
989
|
+
var layer = {
|
|
990
|
+
canvas: canvas,
|
|
991
|
+
context: context,
|
|
992
|
+
parentContext: parentContext
|
|
993
|
+
};
|
|
994
|
+
this._canvasContext = context;
|
|
995
|
+
return layer;
|
|
996
|
+
},
|
|
997
|
+
|
|
998
|
+
drawTransparencyLayer: function(transparencyLayer){
|
|
999
|
+
this._canvasContext = transparencyLayer.parentContext;
|
|
1000
|
+
this._canvasContext.resetTransform();
|
|
1001
|
+
this._canvasContext.drawImage(transparencyLayer.canvas, 0, 0);
|
|
1002
|
+
this._reusableTransparencyLayer = transparencyLayer;
|
|
1003
|
+
},
|
|
1004
|
+
|
|
920
1005
|
// ----------------------------------------------------------------------
|
|
921
1006
|
// MARK: - Clipping
|
|
922
1007
|
|
|
@@ -1296,29 +1381,25 @@ JSClass("UIHTMLDisplayServerCanvasContextPath", JSPath, {
|
|
|
1296
1381
|
canvasOperations: function(prototype, transform){
|
|
1297
1382
|
var operations = [];
|
|
1298
1383
|
var i, l;
|
|
1299
|
-
var
|
|
1300
|
-
var
|
|
1301
|
-
var segment;
|
|
1384
|
+
var elements = this.elements;
|
|
1385
|
+
var element;
|
|
1302
1386
|
var point;
|
|
1303
1387
|
var cp1;
|
|
1304
1388
|
var cp2;
|
|
1305
|
-
for (i = 0, l =
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
if (subpath.closed){
|
|
1389
|
+
for (i = 0, l = elements.length; i < l; ++i){
|
|
1390
|
+
element = elements[i];
|
|
1391
|
+
if (element.type === JSPathElement.Type.move){
|
|
1392
|
+
point = transform.convertPointToTransform(element.point);
|
|
1393
|
+
operations.push({method: prototype.moveTo, arguments: [point.x, point.y]});
|
|
1394
|
+
}else if (element.type === JSPathElement.Type.line){
|
|
1395
|
+
point = transform.convertPointToTransform(element.point);
|
|
1396
|
+
operations.push({method: prototype.lineTo, arguments: [point.x, point.y]});
|
|
1397
|
+
}else if (element.type === JSPathElement.Type.cubicCurve){
|
|
1398
|
+
point = transform.convertPointToTransform(element.curve.p2);
|
|
1399
|
+
cp1 = transform.convertPointToTransform(element.curve.cp1);
|
|
1400
|
+
cp2 = transform.convertPointToTransform(element.curve.cp2);
|
|
1401
|
+
operations.push({method: prototype.bezierCurveTo, arguments: [cp1.x, cp1.y, cp2.x, cp2.y, point.x, point.y]});
|
|
1402
|
+
}else if (element.type === JSPathElement.Type.close){
|
|
1322
1403
|
operations.push({method: prototype.closePath, arguments: []});
|
|
1323
1404
|
}
|
|
1324
1405
|
}
|
|
@@ -99,6 +99,11 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
99
99
|
context.translateBy(point.x, point.y + this.font.ascender);
|
|
100
100
|
context.setFont(this.font);
|
|
101
101
|
context.setFillColor(this.attributes.textColor);
|
|
102
|
+
if (this.attributes.strokeWidth){
|
|
103
|
+
context.setLineWidth(this.attributes.strokeWidth);
|
|
104
|
+
context.setStrokeColor(this.attributes.strokeColor);
|
|
105
|
+
context.setTextDrawingMode(JSContext.TextDrawingMode.fillStroke);
|
|
106
|
+
}
|
|
102
107
|
context.showText(this.textNode.nodeValue);
|
|
103
108
|
context.restore();
|
|
104
109
|
}
|
|
@@ -37,6 +37,7 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
|
|
|
37
37
|
this._lineElementQueue = [];
|
|
38
38
|
},
|
|
39
39
|
|
|
40
|
+
_useCanvasMetricsForMeasure: true,
|
|
40
41
|
_suggestedHTMLLineLayout: null,
|
|
41
42
|
|
|
42
43
|
canvasContext: null,
|
|
@@ -204,6 +205,14 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
|
|
|
204
205
|
span.style.color = textColor ? textColor.cssString() : 'black';
|
|
205
206
|
span.style.backgroundColor = backgroundColor ? backgroundColor.cssString() : '';
|
|
206
207
|
span.style.pointerEvents = 'none';
|
|
208
|
+
|
|
209
|
+
// Stroke
|
|
210
|
+
var strokeColor = attributes[JSAttributedString.Attribute.strokeColor] || null;
|
|
211
|
+
var strokeWidth = attributes[JSAttributedString.Attribute.strokeWidth] || 0;
|
|
212
|
+
if (strokeWidth > 0){
|
|
213
|
+
span.style.webkitTextStrokeWidth = '%fpx'.sprintf(strokeWidth);
|
|
214
|
+
span.style.webkitTextStrokeColor = strokeColor ? strokeColor.cssString() : 'black';
|
|
215
|
+
}
|
|
207
216
|
},
|
|
208
217
|
|
|
209
218
|
_styleAttachmentElementWithAttributes: function(span, attributes, attachment){
|
|
@@ -260,10 +269,16 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
|
|
|
260
269
|
runDescriptor.attachment = attachment;
|
|
261
270
|
}else{
|
|
262
271
|
if (!newline){
|
|
263
|
-
if (
|
|
264
|
-
|
|
272
|
+
if (this._useCanvasMetricsForMeasure){
|
|
273
|
+
if (attributes[JSAttributedString.Attribute.maskCharacter] !== undefined){
|
|
274
|
+
metrics = this.canvasContext.measureText(attributes[JSAttributedString.Attribute.maskCharacter]);
|
|
275
|
+
}else{
|
|
276
|
+
metrics = this.canvasContext.measureText(iterator.utf16);
|
|
277
|
+
}
|
|
265
278
|
}else{
|
|
266
|
-
metrics =
|
|
279
|
+
metrics = {
|
|
280
|
+
width: runDescriptor.font.widthOfString(iterator.utf16)
|
|
281
|
+
};
|
|
267
282
|
}
|
|
268
283
|
usedWidth += metrics.width;
|
|
269
284
|
runDescriptor.userPerceivedCharacterWidths.push(metrics.width);
|
|
@@ -2229,17 +2229,19 @@ JSClass("UIListView", UIScrollView, {
|
|
|
2229
2229
|
|
|
2230
2230
|
_contextSelectCell: function(cell, location){
|
|
2231
2231
|
if (this.delegate && this.delegate.menuForListViewCellAtIndexPath){
|
|
2232
|
+
if (this._selectionContainsIndexPath(cell.indexPath)){
|
|
2233
|
+
this._contextSelectedIndexPaths = JSCopy(this._selectedIndexPaths);
|
|
2234
|
+
}else{
|
|
2235
|
+
this._contextSelectedIndexPaths = [cell.indexPath];
|
|
2236
|
+
}
|
|
2232
2237
|
var menu = this.delegate.menuForListViewCellAtIndexPath(this, cell.indexPath);
|
|
2233
2238
|
if (menu !== null){
|
|
2234
|
-
if (this._selectionContainsIndexPath(cell.indexPath)){
|
|
2235
|
-
this._contextSelectedIndexPaths = JSCopy(this._selectedIndexPaths);
|
|
2236
|
-
}else{
|
|
2237
|
-
this._contextSelectedIndexPaths = [cell.indexPath];
|
|
2238
|
-
}
|
|
2239
2239
|
this._updateVisibleCellStates();
|
|
2240
2240
|
var locationInCell = this.convertPointToView(location, cell);
|
|
2241
2241
|
menu.delegate = this;
|
|
2242
2242
|
menu.openAtLocationInContextView(locationInCell, cell);
|
|
2243
|
+
}else{
|
|
2244
|
+
this._contextSelectedIndexPaths = [];
|
|
2243
2245
|
}
|
|
2244
2246
|
}
|
|
2245
2247
|
},
|