@breakside/jskit 2022.22.2 → 2022.24.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/JS/XMLSerializer.js +9 -4
- package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
- package/Frameworks/DOM.jsframework/sources.json +10 -3
- package/Frameworks/FontKit.jsframework/Info.json +2 -2
- package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
- package/Frameworks/FontKit.jsframework/sources.json +34 -2
- package/Frameworks/Foundation.jsframework/Info.json +2 -2
- package/Frameworks/Foundation.jsframework/JS/JSAttributedString.js +347 -25
- package/Frameworks/Foundation.jsframework/JS/JSFont.js +39 -15
- package/Frameworks/Foundation.jsframework/JS/JSFontDescriptor+HTML.js +8 -0
- package/Frameworks/Foundation.jsframework/JS/JSFontDescriptor.js +105 -27
- package/Frameworks/Foundation.jsframework/JS/JSParagraphStyle.js +71 -0
- package/Frameworks/Foundation.jsframework/JS/JSTextAttachment.js +1 -1
- package/Frameworks/Foundation.jsframework/JS/JSTextContainer.js +56 -29
- package/Frameworks/Foundation.jsframework/JS/JSTextFrame.js +2 -32
- package/Frameworks/Foundation.jsframework/JS/JSTextFramesetter.js +125 -22
- package/Frameworks/Foundation.jsframework/JS/JSTextLayoutManager.js +11 -3
- package/Frameworks/Foundation.jsframework/JS/JSTextLine.js +4 -3
- package/Frameworks/Foundation.jsframework/JS/JSTextRun.js +5 -3
- package/Frameworks/Foundation.jsframework/JS/JSTextTypesetter.js +41 -25
- package/Frameworks/Foundation.jsframework/JS/String+JS.js +69 -0
- package/Frameworks/Foundation.jsframework/JS/UnicodeChar.js +8 -0
- package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
- package/Frameworks/Foundation.jsframework/sources.json +170 -8
- package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
- package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
- package/Frameworks/SecurityKit.jsframework/sources.json +43 -2
- package/Info.json +2 -2
- package/Node/Builder.js +20 -9
- package/Node/FrameworkBuilder.js +22 -2
- package/Node/Project.js +22 -2
- package/Node/io.breakside.jskit-bundle.js +2 -2
- package/Node/jskit +8 -7
- 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/CHAxis.js +5 -5
- package/Root/Frameworks/ChartKit/CHPieChart.js +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/DOM/XMLSerializer.js +9 -4
- package/Root/Frameworks/Dispatch/Info.yaml +1 -1
- package/Root/Frameworks/FontKit/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/JSAttributedString.js +347 -25
- package/Root/Frameworks/Foundation/JSFont.js +39 -15
- package/Root/Frameworks/Foundation/JSFontDescriptor+HTML.js +8 -0
- package/Root/Frameworks/Foundation/JSFontDescriptor.js +105 -27
- package/Root/Frameworks/Foundation/JSParagraphStyle.js +71 -0
- package/Root/Frameworks/Foundation/JSTextAttachment.js +1 -1
- package/Root/Frameworks/Foundation/JSTextContainer.js +56 -29
- package/Root/Frameworks/Foundation/JSTextFrame.js +2 -32
- package/Root/Frameworks/Foundation/JSTextFramesetter.js +125 -22
- package/Root/Frameworks/Foundation/JSTextLayoutManager.js +11 -3
- package/Root/Frameworks/Foundation/JSTextLine.js +4 -3
- package/Root/Frameworks/Foundation/JSTextRun.js +5 -3
- package/Root/Frameworks/Foundation/JSTextTypesetter.js +41 -25
- package/Root/Frameworks/Foundation/String+JS.js +69 -0
- package/Root/Frameworks/Foundation/UnicodeChar.js +8 -0
- 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/UIKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/UIHTMLContentEditableTextInputManager.js +36 -0
- package/Root/Frameworks/UIKit/UIHTMLDisplayServer.js +1 -1
- package/Root/Frameworks/UIKit/UIHTMLTextField.js +1 -1
- package/Root/Frameworks/UIKit/UIHTMLTextFrame.js +19 -91
- package/Root/Frameworks/UIKit/UIHTMLTextFramesetter.js +52 -9
- package/Root/Frameworks/UIKit/UIHTMLTextLine.js +95 -30
- package/Root/Frameworks/UIKit/UIHTMLTextRun.js +22 -9
- package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +334 -459
- package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +16 -0
- package/Root/Frameworks/UIKit/UILabel.js +43 -10
- package/Root/Frameworks/UIKit/UIScrollView.js +12 -0
- package/Root/Frameworks/UIKit/UISegmentedControl.js +6 -6
- package/Root/Frameworks/UIKit/UITextAttachmentView.js +1 -1
- package/Root/Frameworks/UIKit/UITextEditor.js +210 -25
- package/Root/Frameworks/UIKit/UITextField.js +58 -31
- package/Root/Frameworks/UIKit/UITextInput.js +3 -1
- package/Root/Frameworks/UIKit/UITextInputManager.js +2 -2
- package/Root/Frameworks/UIKit/UITextLayer.js +39 -26
- package/Root/Frameworks/UIKit/UITokenField.js +4 -4
- package/Root/Frameworks/UIKit/UIView.js +3 -1
- package/Root/Frameworks/UIKit/UIWindow.js +16 -3
- package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
- package/package.json +1 -1
|
@@ -26,40 +26,15 @@
|
|
|
26
26
|
JSClass("UIHTMLTextFrame", JSTextFrame, {
|
|
27
27
|
|
|
28
28
|
element: null,
|
|
29
|
-
|
|
29
|
+
attachmentRuns: null,
|
|
30
30
|
|
|
31
|
-
initWithElement: function(element, lines, size
|
|
31
|
+
initWithElement: function(element, lines, size){
|
|
32
32
|
this.element = element;
|
|
33
|
-
this.
|
|
33
|
+
this.attachmentRuns = [];
|
|
34
34
|
var line;
|
|
35
35
|
var i, l;
|
|
36
36
|
var j, k;
|
|
37
37
|
|
|
38
|
-
// If our element is not in the document, we need to add it so calls
|
|
39
|
-
// to getBoundingClientRect() will work.
|
|
40
|
-
// The HTML framesetter always adds a newly created frame to the document,
|
|
41
|
-
// but it's possible to be removed from the document if we're reusing a
|
|
42
|
-
// frame that's in a view that itself has been removed from the document.
|
|
43
|
-
// After we're done making calls, we'll add it back to the original parent
|
|
44
|
-
// in its original location.
|
|
45
|
-
//
|
|
46
|
-
// UPDATE 2020-07-26 - When text frames are drawn inside a scaled or rotated
|
|
47
|
-
// view, the getBoundingClientRect() based calculations return transformed
|
|
48
|
-
// values, which we don't want. The quickest fix is to ALWAYS remove the
|
|
49
|
-
// frame element from its parent and attach it to the document body so
|
|
50
|
-
// it will be untransformed. This doesn't appear to be a major performance
|
|
51
|
-
// issue, but it would be nice to find another way around. For now, I'm
|
|
52
|
-
// preserving the original code with the addition of `true || ` to always
|
|
53
|
-
// enter the conditional.
|
|
54
|
-
var originalParent = null;
|
|
55
|
-
var originalSibling = null;
|
|
56
|
-
if (true || !this.element.isConnected){
|
|
57
|
-
originalParent = this.element.parentNode;
|
|
58
|
-
originalSibling = this.element.nextSibling;
|
|
59
|
-
this.element.ownerDocument.body.appendChild(this.element);
|
|
60
|
-
this.element.style.visibility = 'hidden';
|
|
61
|
-
}
|
|
62
|
-
|
|
63
38
|
// add all the lines to our element
|
|
64
39
|
for (i = 0, l = lines.length; i < l; ++i){
|
|
65
40
|
line = lines[i];
|
|
@@ -69,38 +44,15 @@ JSClass("UIHTMLTextFrame", JSTextFrame, {
|
|
|
69
44
|
}
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
|
|
73
|
-
// NOTE: this could be a job for the typesetter, but doing so incrementally
|
|
74
|
-
// as runs/lines are created would force a extra layouts that aren't necessary.
|
|
75
|
-
// So we try to force only one layout here and then grab all the metrics
|
|
76
|
-
var origin = JSPoint(0, 0);
|
|
77
|
-
for (i = 0, l = lines.length; i < l; ++i){
|
|
78
|
-
line = lines[i];
|
|
79
|
-
line.recalculateSize();
|
|
80
|
-
line.recalculateTrailingWhitespace();
|
|
81
|
-
line._origin = JSPoint(origin);
|
|
82
|
-
origin.y += line._size.height;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
var attachmentInfo;
|
|
47
|
+
var run;
|
|
86
48
|
for (i = 0, l = lines.length; i < l; ++i){
|
|
87
49
|
line = lines[i];
|
|
88
|
-
for (j = 0, k = line.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// attachmentInfo.attachment.view.frame = JSRect(
|
|
92
|
-
// JSPoint(line.origin.x + attachmentInfo.run.origin.x, line.origin.y + attachmentInfo.run.origin.y),
|
|
93
|
-
// attachmentInfo.attachment.view.frame.size
|
|
94
|
-
// );
|
|
95
|
-
}
|
|
96
|
-
this.attachments.push(attachmentInfo);
|
|
50
|
+
for (j = 0, k = line.attachmentRuns.length; j < k; ++j){
|
|
51
|
+
run = line.attachmentRuns[j];
|
|
52
|
+
this.attachmentRuns.push(run);
|
|
97
53
|
}
|
|
98
54
|
}
|
|
99
55
|
|
|
100
|
-
if (originalParent !== null){
|
|
101
|
-
originalParent.insertBefore(this.element, originalSibling);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
56
|
if (size.width === 0 || size.width === Number.MAX_VALUE){
|
|
105
57
|
this._widthMatchesUsedWidth = true;
|
|
106
58
|
}
|
|
@@ -108,53 +60,30 @@ JSClass("UIHTMLTextFrame", JSTextFrame, {
|
|
|
108
60
|
this._heightMatchesUsedHeight = true;
|
|
109
61
|
}
|
|
110
62
|
|
|
111
|
-
|
|
112
|
-
// we must have properly set the line size and trailingWhitespaceWidth first
|
|
113
|
-
UIHTMLTextFrame.$super.initWithLines.call(this, lines, size, attributes);
|
|
114
|
-
this._updateSizesAndPositions();
|
|
63
|
+
UIHTMLTextFrame.$super.initWithLines.call(this, lines, size);
|
|
115
64
|
this.element.dataset.rangeLocation = this._range.location;
|
|
116
65
|
this.element.dataset.rangeLength = this._range.length;
|
|
117
66
|
this.element.dataset.jstext = "frame";
|
|
118
67
|
},
|
|
119
68
|
|
|
120
|
-
adjustSize: function(newSize){
|
|
121
|
-
UIHTMLTextFrame.$super.adjustSize.call(this, newSize);
|
|
122
|
-
this._updateSizesAndPositions();
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
_updateSizesAndPositions: function(){
|
|
126
|
-
var i, l;
|
|
127
|
-
var line;
|
|
128
|
-
|
|
129
|
-
// set our size
|
|
130
|
-
this.element.style.width = '%dpx'.sprintf(this.size.width);
|
|
131
|
-
this.element.style.height = '%dpx'.sprintf(this.size.height);
|
|
132
|
-
|
|
133
|
-
// position the lines
|
|
134
|
-
for (i = 0, l = this.lines.length; i < l; ++i){
|
|
135
|
-
line = this.lines[i];
|
|
136
|
-
line.element.style.height = '%dpx'.sprintf(line.size.height);
|
|
137
|
-
line.element.style.left = '%dpx'.sprintf(line.origin.x);
|
|
138
|
-
line.element.style.top = '%dpx'.sprintf(line.origin.y);
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
|
|
142
69
|
drawInContextAtPoint: function(context, point){
|
|
143
70
|
if (context.isKindOfClass(UIHTMLDisplayServerCanvasContext)){
|
|
144
71
|
if (this.element.style.visibility == 'hidden'){
|
|
145
72
|
this.element.style.visibility = '';
|
|
146
73
|
}
|
|
147
74
|
context.addExternalElementInRect(this.element, JSRect(point, this.size));
|
|
148
|
-
var
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
75
|
+
var run;
|
|
76
|
+
var attachmentContext;
|
|
77
|
+
for (var i = 0, l = this.attachmentRuns.length; i < l; ++i){
|
|
78
|
+
run = this.attachmentRuns[i];
|
|
79
|
+
attachmentContext = context.displayServer.contextForAttachment(run.attachment);
|
|
80
|
+
if (attachmentContext.element.parentNode !== run.element){
|
|
81
|
+
run.element.appendChild(attachmentContext.element);
|
|
153
82
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
83
|
+
attachmentContext.save();
|
|
84
|
+
attachmentContext.setFillColor(run.attributes.textColor);
|
|
85
|
+
run.attachment.drawInContextAtPoint(attachmentContext, JSPoint.Zero);
|
|
86
|
+
attachmentContext.restore();
|
|
158
87
|
}
|
|
159
88
|
}else{
|
|
160
89
|
UIHTMLTextFrame.$super.drawInContextAtPoint.call(this, context, point);
|
|
@@ -219,7 +148,6 @@ JSClass("UIHTMLTextFrame", JSTextFrame, {
|
|
|
219
148
|
if (this._heightMatchesUsedHeight){
|
|
220
149
|
this._size = JSSize(this._size.width, this._usedSize.height);
|
|
221
150
|
}
|
|
222
|
-
this._updateSizesAndPositions();
|
|
223
151
|
}
|
|
224
152
|
|
|
225
153
|
});
|
|
@@ -26,29 +26,50 @@
|
|
|
26
26
|
JSClass("UIHTMLTextFramesetter", UITextFramesetter, {
|
|
27
27
|
|
|
28
28
|
_domDocument: null,
|
|
29
|
+
_htmlDisplayServer: null,
|
|
29
30
|
_htmlTypesetter: null,
|
|
30
31
|
_frameElement: null,
|
|
31
|
-
|
|
32
|
+
_attachments: null,
|
|
32
33
|
|
|
33
34
|
initWithDocument: function(domDocument, htmlDisplayServer){
|
|
34
|
-
this._htmlTypesetter = UIHTMLTextTypesetter.initWithDocument(domDocument, htmlDisplayServer);
|
|
35
|
-
UIHTMLTextFramesetter.$super.initWithTypesetter.call(this, this._htmlTypesetter);
|
|
36
35
|
this._domDocument = domDocument;
|
|
36
|
+
this._htmlDisplayServer = htmlDisplayServer;
|
|
37
|
+
this._htmlTypesetter = UIHTMLTextTypesetter.initWithDocument(domDocument);
|
|
38
|
+
this._attachments = [];
|
|
39
|
+
UIHTMLTextFramesetter.$super.initWithTypesetter.call(this, this._htmlTypesetter);
|
|
37
40
|
},
|
|
38
41
|
|
|
39
42
|
createFrame: function(size, range, maximumLines){
|
|
40
|
-
this._creatingFrame = true;
|
|
41
43
|
this._createFrameElementIfNeeded();
|
|
42
|
-
var lineBreakMode = this.effectiveLineBreakMode(this.attributes.lineBreakMode, 1, maximumLines);
|
|
43
44
|
this._enqueueElements();
|
|
44
|
-
|
|
45
|
+
var attachmentsByObjectID = {};
|
|
46
|
+
var attachment;
|
|
47
|
+
var i, l;
|
|
48
|
+
for (i = 0, l = this._attachments.length; i < l; ++i){
|
|
49
|
+
attachment = this._attachments[i];
|
|
50
|
+
attachmentsByObjectID[attachment.objectID] = attachment;
|
|
51
|
+
}
|
|
45
52
|
var frame = UIHTMLTextFramesetter.$super.createFrame.call(this, size, range, maximumLines);
|
|
53
|
+
this._attachments = [];
|
|
54
|
+
for (i = 0, l = frame.attachmentRuns.length; i < l; ++i){
|
|
55
|
+
attachment = frame.attachmentRuns[i].attachment;
|
|
56
|
+
this._attachments.push(attachment);
|
|
57
|
+
if (attachment.objectID in attachmentsByObjectID){
|
|
58
|
+
delete attachmentsByObjectID[attachment.objectID];
|
|
59
|
+
}else{
|
|
60
|
+
this._htmlDisplayServer.attachmentInserted(attachment);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (i in attachmentsByObjectID){
|
|
64
|
+
attachment = attachmentsByObjectID[i];
|
|
65
|
+
this._htmlDisplayServer.attachmentRemoved(attachment);
|
|
66
|
+
}
|
|
46
67
|
this._removeQueuedElements();
|
|
47
68
|
return frame;
|
|
48
69
|
},
|
|
49
70
|
|
|
50
|
-
constructFrame: function(lines, size
|
|
51
|
-
return UIHTMLTextFrame.initWithElement(this._frameElement, lines, size
|
|
71
|
+
constructFrame: function(lines, size){
|
|
72
|
+
return UIHTMLTextFrame.initWithElement(this._frameElement, lines, size);
|
|
52
73
|
},
|
|
53
74
|
|
|
54
75
|
_createFrameElementIfNeeded: function(){
|
|
@@ -114,7 +135,29 @@ JSClass("UIHTMLTextFramesetter", UITextFramesetter, {
|
|
|
114
135
|
}
|
|
115
136
|
element = this._htmlTypesetter.dequeueRunElement();
|
|
116
137
|
}
|
|
117
|
-
}
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
_alignLinesInFrame: function(frame){
|
|
141
|
+
UIHTMLTextFramesetter.$super._alignLinesInFrame.call(this, frame);
|
|
142
|
+
this._updateSizesAndPositionsOfLinesInFrame(frame);
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
_updateSizesAndPositionsOfLinesInFrame: function(frame){
|
|
146
|
+
var i, l;
|
|
147
|
+
var line;
|
|
148
|
+
|
|
149
|
+
// set our size
|
|
150
|
+
frame.element.style.width = '%dpx'.sprintf(frame.size.width);
|
|
151
|
+
frame.element.style.height = '%dpx'.sprintf(frame.size.height);
|
|
152
|
+
|
|
153
|
+
// position the lines
|
|
154
|
+
for (i = 0, l = frame.lines.length; i < l; ++i){
|
|
155
|
+
line = frame.lines[i];
|
|
156
|
+
line.element.style.height = '%dpx'.sprintf(line.size.height);
|
|
157
|
+
line.element.style.left = '%dpx'.sprintf(line.origin.x);
|
|
158
|
+
line.element.style.top = '%dpx'.sprintf(line.origin.y);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
118
161
|
|
|
119
162
|
});
|
|
120
163
|
|
|
@@ -24,28 +24,29 @@ JSClass("UIHTMLTextLine", JSTextLine, {
|
|
|
24
24
|
|
|
25
25
|
element: null,
|
|
26
26
|
emptyTextNode: null,
|
|
27
|
-
|
|
28
|
-
overflowed: false,
|
|
27
|
+
attachmentRuns: null,
|
|
29
28
|
fontLineHeight: 0,
|
|
29
|
+
canvasContext: null,
|
|
30
30
|
|
|
31
|
-
initWithElementAndFont: function(element, font, height, location){
|
|
31
|
+
initWithElementAndFont: function(element, font, height, location, canvasContext){
|
|
32
32
|
UIHTMLTextLine.$super.initWithHeight.call(this, height, -font.displayDescender, location);
|
|
33
33
|
this.element = element;
|
|
34
34
|
element.style.font = font.cssString(height);
|
|
35
35
|
this.emptyTextNode = element.appendChild(element.ownerDocument.createTextNode('\u200B'));
|
|
36
36
|
this.fontLineHeight = font.displayLineHeight;
|
|
37
|
-
this.
|
|
37
|
+
this.attachmentRuns = [];
|
|
38
38
|
this.element.dataset.rangeLocation = location;
|
|
39
39
|
this.element.dataset.rangeLength = 0;
|
|
40
40
|
this.element.dataset.jstext = "line";
|
|
41
|
+
this.canvasContext = canvasContext;
|
|
41
42
|
},
|
|
42
43
|
|
|
43
|
-
initWithElement: function(element, runs, trailingWhitespaceWidth,
|
|
44
|
+
initWithElement: function(element, runs, trailingWhitespaceWidth, attachmentRuns, canvasContext){
|
|
44
45
|
// constructing this.element before super init because super init calls
|
|
45
46
|
// this.align, which neesd to use this.element
|
|
46
47
|
UIHTMLTextLine.$super.initWithRuns.call(this, runs, trailingWhitespaceWidth);
|
|
47
48
|
this.element = element;
|
|
48
|
-
this.
|
|
49
|
+
this.attachmentRuns = attachmentRuns || [];
|
|
49
50
|
var run;
|
|
50
51
|
for (var i = 0, l = runs.length; i < l; ++i){
|
|
51
52
|
run = this.runs[i];
|
|
@@ -56,6 +57,7 @@ JSClass("UIHTMLTextLine", JSTextLine, {
|
|
|
56
57
|
this.element.dataset.rangeLocation = this._range.location;
|
|
57
58
|
this.element.dataset.rangeLength = this._range.length;
|
|
58
59
|
this.element.dataset.jstext = "line";
|
|
60
|
+
this.canvasContext = canvasContext;
|
|
59
61
|
},
|
|
60
62
|
|
|
61
63
|
// verticallyAlignRuns: function(){
|
|
@@ -63,39 +65,102 @@ JSClass("UIHTMLTextLine", JSTextLine, {
|
|
|
63
65
|
// },
|
|
64
66
|
|
|
65
67
|
truncatedLine: function(width, token){
|
|
66
|
-
if (
|
|
68
|
+
if (width + 0.1 >= this._size.width){
|
|
67
69
|
return this;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
if (token === undefined){
|
|
71
|
-
token =
|
|
73
|
+
token = "\u2026";
|
|
74
|
+
}
|
|
75
|
+
var line = this.copy();
|
|
76
|
+
|
|
77
|
+
// get rid of any runs that put us over the limit
|
|
78
|
+
var runIndex = line.runs.length - 1;
|
|
79
|
+
while (runIndex > 0 && line.size.width - line.runs[runIndex].size.width >= width){
|
|
80
|
+
line.size.width -= line.runs[runIndex].size.width;
|
|
81
|
+
line.range.length -= line.runs[runIndex].range.length;
|
|
82
|
+
line.element.removeChild(line.runs[runIndex].element);
|
|
83
|
+
line.runs.pop();
|
|
84
|
+
--runIndex;
|
|
72
85
|
}
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
// Find the run that has space for ellipis
|
|
88
|
+
var run;
|
|
89
|
+
var metrics = null;
|
|
90
|
+
do {
|
|
91
|
+
run = line.runs[runIndex];
|
|
92
|
+
if (!run.attachment){
|
|
93
|
+
this.canvasContext.font = run.font.cssString();
|
|
94
|
+
metrics = this.canvasContext.measureText(token);
|
|
95
|
+
if (line.size.width - run.size.width + metrics.width <= width){
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
line.element.removeChild(run.element);
|
|
100
|
+
line.runs.pop();
|
|
101
|
+
line.size.width -= run.size.width;
|
|
102
|
+
line.range.length -= run.range.length;
|
|
103
|
+
--runIndex;
|
|
104
|
+
}while (runIndex >= 0);
|
|
105
|
+
|
|
106
|
+
// Bail if there's no room for even the token
|
|
107
|
+
if (runIndex < 0){
|
|
108
|
+
return line;
|
|
88
109
|
}
|
|
89
110
|
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
if (metrics !== null){
|
|
112
|
+
var span = this.element.ownerDocument.createElement("span");
|
|
113
|
+
span.setAttribute("style", run.element.getAttribute("style"));
|
|
114
|
+
span.appendChild(this.element.ownerDocument.createTextNode(token));
|
|
115
|
+
var tokenRun = UIHTMLTextRun.initWithElement(span, run.font, run.attributes, JSRange.Zero);
|
|
116
|
+
tokenRun.size.width = metrics.width;
|
|
117
|
+
line.runs.push(tokenRun);
|
|
118
|
+
line.element.appendChild(tokenRun.element);
|
|
119
|
+
line.size.width += tokenRun.size.width;
|
|
120
|
+
|
|
121
|
+
var iterator = run.textNode.nodeValue.userPerceivedCharacterIterator(run.textNode.nodeValue.length - 1);
|
|
122
|
+
while (iterator.character !== null && iterator.isMandatoryLineBreak){
|
|
123
|
+
iterator.decrement();
|
|
124
|
+
run.range.length -= iterator.range.length;
|
|
125
|
+
line.range.length -= iterator.range.length;
|
|
126
|
+
}
|
|
127
|
+
while (iterator.character !== null && line.size.width > width){
|
|
128
|
+
metrics = this.canvasContext.measureText(iterator.utf16);
|
|
129
|
+
run.size.width -= metrics.width;
|
|
130
|
+
run.range.length -= iterator.range.length;
|
|
131
|
+
line.size.width -= metrics.width;
|
|
132
|
+
line.range.length -= iterator.range.length;
|
|
133
|
+
run.textNode.nodeValue = run.textNode.nodeValue.substr(0, run.textNode.nodeValue.length - iterator.range.length);
|
|
134
|
+
iterator.decrement();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (run.range.length === 0){
|
|
138
|
+
line.element.removeChild(line.runs[line.runs.length - 2].element);
|
|
139
|
+
line.runs.splice(line.runs.length - 2, 1);
|
|
140
|
+
}
|
|
92
141
|
|
|
93
|
-
|
|
94
|
-
// but this would also possibly require backing up 1+ characters to make enough room for the ellipis
|
|
142
|
+
tokenRun.origin.x = line.size.width - tokenRun.size.width;
|
|
95
143
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
144
|
+
line.verticallyAlignRuns();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return line;
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
copy: function(){
|
|
151
|
+
var line = UIHTMLTextLine.$super.copy.call(this);
|
|
152
|
+
line.element = this.element.cloneNode();
|
|
153
|
+
if (this.emptyTextNode !== null){
|
|
154
|
+
line.emptyTextNode = this.emptyTextNode.cloneNode();
|
|
155
|
+
line.element.appendChild(line.emptyTextNode);
|
|
156
|
+
}
|
|
157
|
+
for (var i = 0, l = line.runs.length; i < l; ++i){
|
|
158
|
+
line.element.appendChild(line.runs[i].element);
|
|
159
|
+
}
|
|
160
|
+
line.attachmentRuns = JSCopy(this.attachmentRuns);
|
|
161
|
+
line.fontLineHeight = this.fontLineHeight;
|
|
162
|
+
this.canvasContext = this.canvasContext;
|
|
163
|
+
return line;
|
|
99
164
|
},
|
|
100
165
|
|
|
101
166
|
rectForEmptyCharacter: function(){
|
|
@@ -179,7 +244,7 @@ JSClass("UIHTMLTextLine", JSTextLine, {
|
|
|
179
244
|
this.element.dataset.rangeLocation = this._range.location;
|
|
180
245
|
this.element.dataset.rangeLength = this._range.length;
|
|
181
246
|
return diff;
|
|
182
|
-
}
|
|
247
|
+
},
|
|
183
248
|
|
|
184
249
|
});
|
|
185
250
|
|
|
@@ -39,6 +39,7 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
39
39
|
// Only the UIHTMLTextFrame does the final measuring.
|
|
40
40
|
if (!this.attachment){
|
|
41
41
|
this._size.height = font.displayLineHeight;
|
|
42
|
+
this.baseline = -font.displayDescender;
|
|
42
43
|
}
|
|
43
44
|
if (element.childNodes.length > 0 && element.firstChild.nodeType === element.TEXT_NODE){
|
|
44
45
|
this.textNode = element.firstChild;
|
|
@@ -59,7 +60,6 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
59
60
|
if (mask){
|
|
60
61
|
this._maskFactor = mask.length;
|
|
61
62
|
}
|
|
62
|
-
this.baseline = -font.displayDescender;
|
|
63
63
|
this.element.dataset.rangeLocation = this._range.location;
|
|
64
64
|
this.element.dataset.rangeLength = this._range.length;
|
|
65
65
|
this.element.dataset.jstext = "run";
|
|
@@ -118,8 +118,8 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
118
118
|
},
|
|
119
119
|
|
|
120
120
|
characterIndexAtPoint: function(point){
|
|
121
|
-
var min =
|
|
122
|
-
var max = this.range.
|
|
121
|
+
var min = this.range.location;
|
|
122
|
+
var max = this.range.end;
|
|
123
123
|
var mid;
|
|
124
124
|
var rect;
|
|
125
125
|
var i = 0;
|
|
@@ -145,7 +145,7 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
-
return
|
|
148
|
+
return min;
|
|
149
149
|
},
|
|
150
150
|
|
|
151
151
|
_textFrameConstructionWidthOfRange: function(range){
|
|
@@ -169,17 +169,17 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
169
169
|
rectForCharacterAtIndex: function(index){
|
|
170
170
|
// attachment run
|
|
171
171
|
if (this.textNode === null){
|
|
172
|
-
if (index ===
|
|
172
|
+
if (index === this.range.location){
|
|
173
173
|
return JSRect(0, 0, this.size.width, this.size.height);
|
|
174
174
|
}
|
|
175
|
-
if (index ===
|
|
175
|
+
if (index === this.range.end){
|
|
176
176
|
return JSRect(this.size.width, 0, 0, this.size.height);
|
|
177
177
|
}
|
|
178
178
|
return JSRect.Zero;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// at end, which we know without measuring
|
|
182
|
-
if (index >= this.range.
|
|
182
|
+
if (index >= this.range.end){
|
|
183
183
|
return JSRect(this.size.width, 0, 0, this.size.height);
|
|
184
184
|
}
|
|
185
185
|
|
|
@@ -190,8 +190,9 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
190
190
|
// Create a DOM range for the character in the span because the DOM range can
|
|
191
191
|
// report its size and coordinates
|
|
192
192
|
var rect;
|
|
193
|
-
index
|
|
194
|
-
|
|
193
|
+
var localIndex = index - this.range.location;
|
|
194
|
+
localIndex *= this._maskFactor;
|
|
195
|
+
var iterator = sharedElementForSizing.firstChild.nodeValue.userPerceivedCharacterIterator(localIndex);
|
|
195
196
|
sharedDomRange.setStart(sharedElementForSizing.firstChild, iterator.range.location);
|
|
196
197
|
sharedDomRange.setEnd(sharedElementForSizing.firstChild, iterator.range.end);
|
|
197
198
|
var clientRect = this._pickCorrectClientRectFromRects(sharedDomRange.getClientRects());
|
|
@@ -210,6 +211,7 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
210
211
|
sharedElementForSizing.style.position = "absolute";
|
|
211
212
|
sharedElementForSizing.style.zIndex = -100;
|
|
212
213
|
sharedElementForSizing.style.right = "0";
|
|
214
|
+
sharedElementForSizing.style.whiteSpace = "pre";
|
|
213
215
|
sharedElementForSizing.ownerDocument.body.appendChild(sharedElementForSizing);
|
|
214
216
|
}
|
|
215
217
|
sharedElementForSizing.style.font = this.element.style.font;
|
|
@@ -256,6 +258,17 @@ JSClass("UIHTMLTextRun", JSTextRun, {
|
|
|
256
258
|
return diff;
|
|
257
259
|
},
|
|
258
260
|
|
|
261
|
+
copy: function(){
|
|
262
|
+
var run = UIHTMLTextRun.$super.copy.call(this);
|
|
263
|
+
run.element = this.element.cloneNode();
|
|
264
|
+
if (this.textNode !== null){
|
|
265
|
+
run.textNode = this.textNode.cloneNode();
|
|
266
|
+
run.element.appendChild(run.textNode);
|
|
267
|
+
}
|
|
268
|
+
run._maskFactor = this._maskFactor;
|
|
269
|
+
return run;
|
|
270
|
+
}
|
|
271
|
+
|
|
259
272
|
});
|
|
260
273
|
|
|
261
274
|
var sharedElementForSizing = null;
|