@breakside/jskit 2026.11.0 → 2026.27.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 (87) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/JS/FNTOpenTypeFont.js +331 -22
  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 +56 -1
  8. package/Frameworks/Foundation.jsframework/JS/JSContext.js +44 -17
  9. package/Frameworks/Foundation.jsframework/JS/JSCubicBezier.js +54 -1
  10. package/Frameworks/Foundation.jsframework/JS/JSFont.js +8 -9
  11. package/Frameworks/Foundation.jsframework/JS/JSGradient.js +28 -2
  12. package/Frameworks/Foundation.jsframework/JS/JSImage+HTML.js +27 -1
  13. package/Frameworks/Foundation.jsframework/JS/JSNumberFormatter.js +23 -1
  14. package/Frameworks/Foundation.jsframework/JS/JSPath.js +194 -6
  15. package/Frameworks/Foundation.jsframework/JS/JSPoint.js +56 -0
  16. package/Frameworks/Foundation.jsframework/JS/JSTextRun.js +21 -4
  17. package/Frameworks/Foundation.jsframework/JS/JSTextStorage.js +5 -0
  18. package/Frameworks/Foundation.jsframework/JS/JSTextTypesetter.js +6 -1
  19. package/Frameworks/Foundation.jsframework/JS/JSXMLParser.js +1 -1
  20. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  21. package/Frameworks/Foundation.jsframework/sources.json +1 -0
  22. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  23. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  24. package/Info.json +2 -2
  25. package/Node/io.breakside.jskit-bundle.js +2 -2
  26. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  27. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  28. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  29. package/Root/Frameworks/CSSOM/CSSTokenizer.js +633 -470
  30. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  31. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  32. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  33. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  34. package/Root/Frameworks/DOM/Info.yaml +1 -1
  35. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  36. package/Root/Frameworks/FontKit/FNTOpenTypeFont.js +331 -22
  37. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  38. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  39. package/Root/Frameworks/Foundation/JSAttributedString.js +56 -1
  40. package/Root/Frameworks/Foundation/JSContext.js +44 -17
  41. package/Root/Frameworks/Foundation/JSCubicBezier.js +54 -1
  42. package/Root/Frameworks/Foundation/JSFont.js +8 -9
  43. package/Root/Frameworks/Foundation/JSGradient.js +28 -2
  44. package/Root/Frameworks/Foundation/JSImage+HTML.js +27 -1
  45. package/Root/Frameworks/Foundation/JSNumberFormatter.js +23 -1
  46. package/Root/Frameworks/Foundation/JSPath.js +194 -6
  47. package/Root/Frameworks/Foundation/JSPoint.js +56 -0
  48. package/Root/Frameworks/Foundation/JSTextRun.js +21 -4
  49. package/Root/Frameworks/Foundation/JSTextStorage.js +5 -0
  50. package/Root/Frameworks/Foundation/JSTextTypesetter.js +6 -1
  51. package/Root/Frameworks/Foundation/JSXMLParser.js +1 -1
  52. package/Root/Frameworks/ImageKit/IKHTMLCanvasBitmapContext.js +187 -101
  53. package/Root/Frameworks/ImageKit/IKNodeBitmapContext.js +4 -4
  54. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  55. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  56. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  57. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  58. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  59. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  60. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  61. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  62. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  63. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  64. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  65. package/Root/Frameworks/TestKit/TKAssert.js +4 -4
  66. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  67. package/Root/Frameworks/UIKit/UIApplication.js +9 -1
  68. package/Root/Frameworks/UIKit/UICollectionView.js +4 -0
  69. package/Root/Frameworks/UIKit/UIColorPanel.js +46 -0
  70. package/Root/Frameworks/UIKit/UIColorWell.js +8 -0
  71. package/Root/Frameworks/UIKit/UIHTMLDisplayServer.js +21 -2
  72. package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +150 -69
  73. package/Root/Frameworks/UIKit/UIHTMLTextRun.js +5 -0
  74. package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +18 -3
  75. package/Root/Frameworks/UIKit/UIListView.js +7 -5
  76. package/Root/Frameworks/UIKit/UIMenu.js +50 -32
  77. package/Root/Frameworks/UIKit/UIMenuItem.js +12 -0
  78. package/Root/Frameworks/UIKit/UIMenuView.js +27 -5
  79. package/Root/Frameworks/UIKit/UIPlatform.js +7 -0
  80. package/Root/Frameworks/UIKit/UIPopupButton.js +7 -1
  81. package/Root/Frameworks/UIKit/UIResponder.js +8 -0
  82. package/Root/Frameworks/UIKit/UITextEditor.js +31 -7
  83. package/Root/Frameworks/UIKit/UITextField.js +7 -0
  84. package/Root/Frameworks/UIKit/UITokenField.js +65 -0
  85. package/Root/Frameworks/UIKit/UIToolbar.js +1 -1
  86. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  87. package/package.json +1 -1
@@ -77,9 +77,14 @@ JSClass("JSTextTypesetter", JSObject, {
77
77
  var attributes = this._attributedString.attributesAtIndex(range.location);
78
78
  attributes = this.resolveAttributes(attributes);
79
79
  var font = attributes.font;
80
+ if (this.useDisplayMetrics){
81
+ return JSTextLine.initWithHeight(font.displayLineHeight, -font.displayDescender, range.location);
82
+ }
80
83
  return JSTextLine.initWithHeight(font.lineHeight, -font.descender, range.location);
81
84
  },
82
85
 
86
+ useDisplayMetrics: false,
87
+
83
88
  _createLineFromLayout: function(layout){
84
89
  // Create runs from the adjusted run descriptors
85
90
  var runs = [];
@@ -88,7 +93,7 @@ JSClass("JSTextTypesetter", JSObject, {
88
93
  var runDescriptor;
89
94
  for (var i = 0, l = layout.runDescriptors.length; i < l; ++i){
90
95
  runDescriptor = layout.runDescriptors[i];
91
- run = JSTextRun.initWithGlyphs(runDescriptor.glyphs, runDescriptor.glyphCharacterLengths, runDescriptor.font, runDescriptor.attributes, JSRange(runDescriptor.location, runDescriptor.length));
96
+ run = JSTextRun.initWithGlyphs(runDescriptor.glyphs, runDescriptor.glyphCharacterLengths, runDescriptor.font, runDescriptor.attributes, JSRange(runDescriptor.location, runDescriptor.length), this.useDisplayMetrics);
92
97
  run.origin.x = x;
93
98
  x += run.size.width;
94
99
  runs.push(run);
@@ -475,7 +475,7 @@ JSClass("JSXMLParser", JSObject, {
475
475
  }
476
476
  obj = readObject();
477
477
  }
478
- if (!this.isStopped && this.delegate.xmlParserDidEndDocument){
478
+ if (!this.isStopped && this.delegate && this.delegate.xmlParserDidEndDocument){
479
479
  this.delegate.xmlParserDidEndDocument(this);
480
480
  }
481
481
  }catch (e){
@@ -167,9 +167,11 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
167
167
  drawPath: function(drawingMode){
168
168
  var path = this.path.copy();
169
169
  this.enqueueOperation(function(state, completion, target){
170
+ this.canvasContext.save();
170
171
  this.canvasContext.setTransform(1, 0, 0, 1, 0, 0);
171
172
  this.canvasContext.beginPath();
172
173
  path.addToIKHTMLCanvasContext(this.canvasContext);
174
+ this.canvasContext.restore();
173
175
  switch (drawingMode){
174
176
  case JSContext.DrawingMode.fill:
175
177
  this.canvasContext.fill();
@@ -213,19 +215,21 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
213
215
  return;
214
216
  }
215
217
  var scale = Math.ceil(Math.max(state.transform.a, state.transform.b));
218
+ var size = JSSize(rect.size.width * scale, rect.size.height * scale);
216
219
  var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
217
- maskCanvas.width = maskImage.size.width * scale;
218
- maskCanvas.height = maskImage.size.height * scale;
220
+ maskCanvas.width = size.width;
221
+ maskCanvas.height = size.height;
219
222
  var maskContext = maskCanvas.getContext('2d');
220
223
  maskContext.fillStyle = state.fillColor.cssString();
221
- maskContext.fillRect(0, 0, maskCanvas.width, maskCanvas.height);
224
+ maskContext.fillRect(0, 0, size.width, size.height);
222
225
  maskContext.globalCompositeOperation = 'destination-in';
223
- maskContext.drawImage(imgElement, 0, 0, maskCanvas.width, maskCanvas.height);
226
+ maskContext.drawImage(imgElement, 0, 0, size.width, size.height);
224
227
  this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
225
228
  completion.call(target);
226
229
  }, this);
227
230
  });
228
231
  },
232
+
229
233
  // ----------------------------------------------------------------------
230
234
  // MARK: - Images
231
235
 
@@ -249,17 +253,7 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
249
253
  drawLinearGradient: function(gradient, rect){
250
254
  this.enqueueOperation(function(state, completion, target){
251
255
  this.canvasContext.save();
252
- var canvasGradient = this.canvasContext.createLinearGradient(
253
- rect.origin.x + gradient.start.x * rect.size.width,
254
- rect.origin.y + gradient.start.y * rect.size.height,
255
- rect.origin.x + gradient.end.x * rect.size.width,
256
- rect.origin.y + gradient.end.y * rect.size.height
257
- );
258
- var stop;
259
- for (var i = 0, l = gradient.stops.length; i < l; ++i){
260
- stop = gradient.stops[i];
261
- canvasGradient.addColorStop(stop.position, stop.color.cssString());
262
- }
256
+ var canvasGradient = this._linearGradientForCanvasContext(this.canvasContext, gradient, rect);
263
257
  this.canvasContext.fillStyle = canvasGradient;
264
258
  this.canvasContext.fillRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
265
259
  this.canvasContext.restore();
@@ -269,30 +263,8 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
269
263
 
270
264
  drawRadialGradient: function(gradient, rect){
271
265
  this.enqueueOperation(function(state, completion, target){
272
- var r0 = 0;
273
- var start = JSPoint(
274
- rect.origin.x + gradient.start.x * rect.size.width,
275
- rect.origin.y + gradient.start.y * rect.size.height
276
- );
277
- var end = JSPoint(
278
- rect.origin.x + gradient.end.x * rect.size.width,
279
- rect.origin.y + gradient.end.y * rect.size.height
280
- );
281
- var r1 = start.distanceToPoint(end);
266
+ var canvasGradient = this._radialGradientForCanvasContext(this.canvasContext, gradient, rect);
282
267
  this.canvasContext.save();
283
- var canvasGradient = this.canvasContext.createRadialGradient(
284
- start.x,
285
- start.y,
286
- r0,
287
- start.x,
288
- start.y,
289
- r1
290
- );
291
- var stop;
292
- for (var i = 0, l = gradient.stops.length; i < l; ++i){
293
- stop = gradient.stops[i];
294
- canvasGradient.addColorStop(stop.position, stop.color.cssString());
295
- }
296
268
  this.canvasContext.fillStyle = canvasGradient;
297
269
  this.canvasContext.fillRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
298
270
  this.canvasContext.restore();
@@ -300,22 +272,61 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
300
272
  });
301
273
  },
302
274
 
303
- drawLinearGradientStroke: function(gradient, path){
275
+ drawMaskedLinearGradient: function(gradient, rect, maskImage){
276
+ this.enqueueOperation(function(state, completion, target){
277
+ drawableElementForImage(maskImage, this.canvasContext.canvas.ownerDocument, function(imgElement){
278
+ if (imgElement === null){
279
+ completion.call(target);
280
+ return;
281
+ }
282
+ var scale = Math.ceil(Math.max(state.transform.a, state.transform.b));
283
+ var size = JSSize(rect.size.width * scale, rect.size.height * scale);
284
+ var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
285
+ maskCanvas.width = size.width;
286
+ maskCanvas.height = size.height;
287
+ var maskContext = maskCanvas.getContext('2d');
288
+ var canvasGradient = this._linearGradientForCanvasContext(maskContext, gradient, JSRect(JSPoint.Zero, size));
289
+ maskContext.fillStyle = canvasGradient;
290
+ maskContext.fillRect(0, 0, size.width, size.height);
291
+ maskContext.globalCompositeOperation = 'destination-in';
292
+ maskContext.drawImage(imgElement, 0, 0, size.width, size.height);
293
+ this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
294
+ completion.call(target);
295
+ }, this);
296
+ });
297
+ },
298
+
299
+ drawMaskedRadialGradient: function(gradient, rect, maskImage){
300
+ this.enqueueOperation(function(state, completion, target){
301
+ drawableElementForImage(maskImage, this.canvasContext.canvas.ownerDocument, function(imgElement){
302
+ if (imgElement === null){
303
+ completion.call(target);
304
+ return;
305
+ }
306
+ var scale = Math.ceil(Math.max(state.transform.a, state.transform.b));
307
+ var size = JSSize(rect.size.width * scale, rect.size.height * scale);
308
+ var maskCanvas = this.canvasContext.canvas.ownerDocument.createElement("canvas");
309
+ maskCanvas.width = size.width;
310
+ maskCanvas.height = size.height;
311
+ var maskContext = maskCanvas.getContext('2d');
312
+ var canvasGradient = this._radialGradientForCanvasContext(maskContext, gradient, JSRect(JSPoint.Zero, size));
313
+ maskContext.fillStyle = canvasGradient;
314
+ maskContext.fillRect(0, 0, size.width, size.height);
315
+ maskContext.globalCompositeOperation = 'destination-in';
316
+ maskContext.drawImage(imgElement, 0, 0, size.width, size.height);
317
+ this.canvasContext.drawImage(maskCanvas, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
318
+ completion.call(target);
319
+ }, this);
320
+ });
321
+ },
322
+
323
+ drawLinearGradientStroke: function(gradient, path, alternateRect){
304
324
  this.enqueueOperation(function(state, completion, target){
305
325
  var rect = path.boundingRect;
306
326
  this.canvasContext.save();
307
- this.addPath(path);
308
- var canvasGradient = this.canvasContext.createLinearGradient(
309
- rect.origin.x + gradient.start.x * rect.size.width,
310
- rect.origin.y + gradient.start.y * rect.size.height,
311
- rect.origin.x + gradient.end.x * rect.size.width,
312
- rect.origin.y + gradient.end.y * rect.size.height
313
- );
314
- var stop;
315
- for (var i = 0, l = gradient.stops.length; i < l; ++i){
316
- stop = gradient.stops[i];
317
- canvasGradient.addColorStop(stop.position, stop.color.cssString());
318
- }
327
+ this.canvasContext.beginPath();
328
+ path.addToIKHTMLCanvasContext(this.canvasContext);
329
+ var canvasGradient = this._linearGradientForCanvasContext(this.canvasContext, gradient, alternateRect || rect);
319
330
  this.canvasContext.strokeStyle = canvasGradient;
320
331
  this.canvasContext.stroke();
321
332
  this.canvasContext.restore();
@@ -324,34 +335,13 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
324
335
  this.beginPath();
325
336
  },
326
337
 
327
- drawRadialGradientStroke: function(gradient, path){
338
+ drawRadialGradientStroke: function(gradient, path, alternateRect){
328
339
  this.enqueueOperation(function(state, completion, target){
329
340
  var rect = path.boundingRect;
330
- var r0 = 0;
331
- var start = JSPoint(
332
- rect.origin.x + gradient.start.x * rect.size.width,
333
- rect.origin.y + gradient.start.y * rect.size.height
334
- );
335
- var end = JSPoint(
336
- rect.origin.x + gradient.end.x * rect.size.width,
337
- rect.origin.y + gradient.end.y * rect.size.height
338
- );
339
- var r1 = start.distanceToPoint(end);
340
341
  this.canvasContext.save();
341
- this.addPath(path);
342
- var canvasGradient = this.canvasContext.createRadialGradient(
343
- start.x,
344
- start.y,
345
- r0,
346
- start.x,
347
- start.y,
348
- r1
349
- );
350
- var stop;
351
- for (var i = 0, l = gradient.stops.length; i < l; ++i){
352
- stop = gradient.stops[i];
353
- canvasGradient.addColorStop(stop.position, stop.color.cssString());
354
- }
342
+ this.canvasContext.beginPath();
343
+ path.addToIKHTMLCanvasContext(this.canvasContext);
344
+ var canvasGradient = this._radialGradientForCanvasContext(this.canvasContext, gradient, alternateRect || rect);
355
345
  this.canvasContext.strokeStyle = canvasGradient;
356
346
  this.canvasContext.stroke();
357
347
  this.canvasContext.restore();
@@ -360,6 +350,105 @@ JSClass("IKHTMLCanvasBitmapContext", IKBitmapContext, {
360
350
  this.beginPath();
361
351
  },
362
352
 
353
+ _linearGradientForCanvasContext: function(canvasContext, gradient, rect){
354
+ var canvasGradient = canvasContext.createLinearGradient(
355
+ rect.origin.x + gradient.start.x * rect.size.width,
356
+ rect.origin.y + gradient.start.y * rect.size.height,
357
+ rect.origin.x + gradient.end.x * rect.size.width,
358
+ rect.origin.y + gradient.end.y * rect.size.height
359
+ );
360
+ var stop;
361
+ for (var i = 0, l = gradient.stops.length; i < l; ++i){
362
+ stop = gradient.stops[i];
363
+ canvasGradient.addColorStop(stop.position, stop.color.cssString());
364
+ }
365
+ return canvasGradient;
366
+ },
367
+
368
+ _radialGradientForCanvasContext: function(canvasContext, gradient, rect){
369
+ var r0 = 0;
370
+ var start = JSPoint(
371
+ rect.origin.x + gradient.start.x * rect.size.width,
372
+ rect.origin.y + gradient.start.y * rect.size.height
373
+ );
374
+ var end = JSPoint(
375
+ rect.origin.x + gradient.end.x * rect.size.width,
376
+ rect.origin.y + gradient.end.y * rect.size.height
377
+ );
378
+ var r1 = start.distanceToPoint(end);
379
+ var canvasGradient = canvasContext.createRadialGradient(
380
+ start.x,
381
+ start.y,
382
+ r0,
383
+ start.x,
384
+ start.y,
385
+ r1
386
+ );
387
+ var stop;
388
+ for (var i = 0, l = gradient.stops.length; i < l; ++i){
389
+ stop = gradient.stops[i];
390
+ canvasGradient.addColorStop(stop.position, stop.color.cssString());
391
+ }
392
+ return canvasGradient;
393
+ },
394
+
395
+ // ----------------------------------------------------------------------
396
+ // MARK: - Transparency Layers
397
+
398
+ _reusableTransparencyLayer: null,
399
+
400
+ createTransparencyLayer: function(){
401
+ if (this._reusableTransparencyLayer !== null){
402
+ layer = this._reusableTransparencyLayer;
403
+ this._reusableTransparencyLayer = null;
404
+ layer.context.resetTransform();
405
+ layer.context.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
406
+ this._canvasContextAdoptState(layer.context, this.state);
407
+ layer.parentContext = this.canvasContext;
408
+ this.canvasContext = layer.context;
409
+ return layer;
410
+ }
411
+ var parentContext = this.canvasContext;
412
+ var canvas = this.canvasElement.ownerDocument.createElement("canvas");
413
+ canvas.width = this.canvasElement.width;
414
+ canvas.height = this.canvasElement.height;
415
+ var context = canvas.getContext("2d");
416
+ this._canvasContextAdoptState(context, this.state);
417
+ var layer = {
418
+ canvas: canvas,
419
+ context: context,
420
+ parentContext: parentContext
421
+ };
422
+ this.canvasContext = context;
423
+ return layer;
424
+ },
425
+
426
+ drawTransparencyLayer: function(transparencyLayer){
427
+ this.canvasContext = transparencyLayer.parentContext;
428
+ this.canvasContext.resetTransform();
429
+ this.canvasContext.drawImage(transparencyLayer.canvas, 0, 0);
430
+ this._reusableTransparencyLayer = transparencyLayer;
431
+ },
432
+
433
+ _canvasContextAdoptState: function(context, state){
434
+ context.globalAlpha = state.alpha;
435
+ context.fillStyle = state.fillColor ? state.fillColor.cssString() : '';
436
+ context.strokeStyle = state.strokeColor ? state.strokeColor.cssString() : '';
437
+ context.shadowOffsetX = state.shadowOffset.x;
438
+ context.shadowOffsetY = state.shadowOffset.y;
439
+ context.shadowBlur = state.shadowBlur;
440
+ context.shadowColor = state.shadowColor ? state.shadowColor.cssString() : '';
441
+ context.lineWidth = state.lineWidth;
442
+ context.lineCap = state.lineCap;
443
+ context.lineJoin = state.lineJoin;
444
+ context.miterLimit = state.miterLimit;
445
+ context.lineDashOffset = state.lineDashPhase;
446
+ context.setLineDash(state.lineDashArray);
447
+ var transform = state.transform;
448
+ context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
449
+ context.font = state.font ? state.font.cssString() : '';
450
+ },
451
+
363
452
  // ----------------------------------------------------------------------
364
453
  // MARK: - Text
365
454
 
@@ -502,31 +591,24 @@ JSPath.definePropertiesFromExtensions({
502
591
 
503
592
  addToIKHTMLCanvasContext: function(canvasContext){
504
593
  var i, l;
505
- var j, k;
506
- var subpath;
507
- var segment;
508
- var point;
509
- var cp1;
510
- var cp2;
511
- for (i = 0, l = this.subpaths.length; i < l; ++i){
512
- subpath = this.subpaths[i];
513
- canvasContext.moveTo(subpath.firstPoint.x, subpath.firstPoint.y);
514
- for (j = 0, k = subpath.segments.length; j < k; ++j){
515
- segment = subpath.segments[j];
516
- if (segment.type === JSPath.SegmentType.line){
517
- canvasContext.lineTo(segment.end.x, segment.end.y);
518
- }else if (segment.type === JSPath.SegmentType.curve){
519
- canvasContext.bezierCurveTo(
520
- segment.curve.cp1.x,
521
- segment.curve.cp1.y,
522
- segment.curve.cp2.x,
523
- segment.curve.cp2.y,
524
- segment.curve.p2.x,
525
- segment.curve.p2.y
526
- );
527
- }
528
- }
529
- if (subpath.closed){
594
+ var elements = this.elements;
595
+ var element;
596
+ for (i = 0, l = elements.length; i < l; ++i){
597
+ element = elements[i];
598
+ if (element.type === JSPathElement.Type.move){
599
+ canvasContext.moveTo(element.point.x, element.point.y);
600
+ }else if (element.type === JSPathElement.Type.line){
601
+ canvasContext.lineTo(element.point.x, element.point.y);
602
+ }else if (element.type === JSPathElement.Type.cubicCurve){
603
+ canvasContext.bezierCurveTo(
604
+ element.curve.cp1.x,
605
+ element.curve.cp1.y,
606
+ element.curve.cp2.x,
607
+ element.curve.cp2.y,
608
+ element.curve.p2.x,
609
+ element.curve.p2.y
610
+ );
611
+ }else if (element.type === JSPathElement.Type.close){
530
612
  canvasContext.closePath();
531
613
  }
532
614
  }
@@ -535,6 +617,10 @@ JSPath.definePropertiesFromExtensions({
535
617
  });
536
618
 
537
619
  var drawableElementForImage = function(image, domDocument, completion, target){
620
+ if (image._htmlImage !== undefined && image._htmlImage !== null){
621
+ completion.call(target, image._htmlImage);
622
+ return;
623
+ }
538
624
  var imgElement = domDocument.createElement("img");
539
625
  imgElement.setAttribute("crossorigin", "anonymous");
540
626
  imgElement.src = image.htmlURLString();
@@ -185,10 +185,10 @@ JSClass("IKNodeBitmapContext", IKBitmapContext, {
185
185
  squarePath.addLineToPoint(JSPoint(1, 1));
186
186
  squarePath.addLineToPoint(JSPoint(0, 1));
187
187
  squarePath.close();
188
- var p1 = squarePath.subpaths[0].firstPoint;
189
- var p2 = squarePath.subpaths[0].segments[0].end;
190
- var p3 = squarePath.subpaths[0].segments[1].end;
191
- var p4 = squarePath.subpaths[0].segments[2].end;
188
+ var p1 = squarePath.elements[0].point;
189
+ var p2 = squarePath.elements[1].point;
190
+ var p3 = squarePath.elements[2].point;
191
+ var p4 = squarePath.elements[3].point;
192
192
  for (var i = 0; p1.y < bitmap.size.height; ++p1.y, ++p2.y, ++p3.y, ++p4.y){
193
193
  for (p1.x = 0, p2.x = 1, p3.x = 1, p4.x = 0; p1.x < bitmap.size.width; ++p1.x, ++p2.x, ++p3.x, ++p4.x){
194
194
  r = bitmap.data[i++];
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ImageKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.MediaKitUI
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.NotificationKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2021 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.PDFKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.QRKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SearchKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.SecurityKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKitTesting
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.TestKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -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('TKAssertExactEquals failed, ' + (a) + ' >= ' + (b) + '. ' + (message || ''));
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('TKAssertExactEquals failed, ' + (a) + ' ,+ ' + (b) + '. ' + (message || ''));
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('TKAssertExactEquals failed, ' + (a) + ' > ' + (b) + '. ' + (message || ''));
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('TKAssertExactEquals failed, ' + (a) + ' < ' + (b) + '. ' + (message || ''));
169
+ throw TKAssertion('TKAssertGreaterThanOrEquals failed, ' + (a) + ' < ' + (b) + '. ' + (message || ''));
170
170
  }
171
171
  };
172
172
 
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKit
3
- JSBundleVersion: 2026.11.0
3
+ JSBundleVersion: 2026.27.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -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)