@next2d/renderer 2.0.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/LICENSE +21 -0
- package/README.md +11 -0
- package/package.json +31 -0
- package/src/Command/service/CommandInitializeContextService.d.ts +11 -0
- package/src/Command/service/CommandInitializeContextService.js +27 -0
- package/src/Command/service/CommandRemoveCacheService.d.ts +10 -0
- package/src/Command/service/CommandRemoveCacheService.js +24 -0
- package/src/Command/service/CommandResizeService.d.ts +12 -0
- package/src/Command/service/CommandResizeService.js +27 -0
- package/src/Command/usecase/CommandCaptureUseCase.d.ts +13 -0
- package/src/Command/usecase/CommandCaptureUseCase.js +53 -0
- package/src/Command/usecase/CommandRenderUseCase.d.ts +11 -0
- package/src/Command/usecase/CommandRenderUseCase.js +70 -0
- package/src/CommandController.d.ts +38 -0
- package/src/CommandController.js +102 -0
- package/src/DisplayObject/service/DisplayObjectGetBlendModeService.d.ts +11 -0
- package/src/DisplayObject/service/DisplayObjectGetBlendModeService.js +45 -0
- package/src/DisplayObjectContainer/usecase/DisplayObjectContainerClipRenderUseCase.d.ts +11 -0
- package/src/DisplayObjectContainer/usecase/DisplayObjectContainerClipRenderUseCase.js +29 -0
- package/src/DisplayObjectContainer/usecase/DisplayObjectContainerRenderUseCase.d.ts +12 -0
- package/src/DisplayObjectContainer/usecase/DisplayObjectContainerRenderUseCase.js +120 -0
- package/src/RendererUtil.d.ts +136 -0
- package/src/RendererUtil.js +214 -0
- package/src/Shape/service/ShapeCommandService.d.ts +11 -0
- package/src/Shape/service/ShapeCommandService.js +252 -0
- package/src/Shape/usecase/ShapeClipRenderUseCase.d.ts +11 -0
- package/src/Shape/usecase/ShapeClipRenderUseCase.js +33 -0
- package/src/Shape/usecase/ShapeRenderUseCase.d.ts +11 -0
- package/src/Shape/usecase/ShapeRenderUseCase.js +154 -0
- package/src/TextField/service/TextFieldGenerateFontStyleService.d.ts +11 -0
- package/src/TextField/service/TextFieldGenerateFontStyleService.js +19 -0
- package/src/TextField/service/TextFiledGetAlignOffsetService.d.ts +15 -0
- package/src/TextField/service/TextFiledGetAlignOffsetService.js +33 -0
- package/src/TextField/usecase/TextFieldDrawOffscreenCanvasUseCase.d.ts +15 -0
- package/src/TextField/usecase/TextFieldDrawOffscreenCanvasUseCase.js +272 -0
- package/src/TextField/usecase/TextFieldRenderUseCase.d.ts +11 -0
- package/src/TextField/usecase/TextFieldRenderUseCase.js +150 -0
- package/src/Video/usecase/VideoRenderUseCase.d.ts +12 -0
- package/src/Video/usecase/VideoRenderUseCase.js +88 -0
- package/src/index.d.ts +2 -0
- package/src/index.js +26 -0
- package/src/interface/IBlendMode.d.ts +1 -0
- package/src/interface/IBlendMode.js +1 -0
- package/src/interface/IMessage.d.ts +11 -0
- package/src/interface/IMessage.js +1 -0
- package/src/interface/INode.d.ts +7 -0
- package/src/interface/INode.js +1 -0
- package/src/interface/IRGBA.d.ts +6 -0
- package/src/interface/IRGBA.js +1 -0
- package/src/interface/ITextData.d.ts +8 -0
- package/src/interface/ITextData.js +1 -0
- package/src/interface/ITextFieldAutoSize.d.ts +1 -0
- package/src/interface/ITextFieldAutoSize.js +1 -0
- package/src/interface/ITextFormat.d.ts +14 -0
- package/src/interface/ITextFormat.js +1 -0
- package/src/interface/ITextFormatAlign.d.ts +1 -0
- package/src/interface/ITextFormatAlign.js +1 -0
- package/src/interface/ITextObject.d.ts +12 -0
- package/src/interface/ITextObject.js +1 -0
- package/src/interface/ITextObjectMode.d.ts +1 -0
- package/src/interface/ITextObjectMode.js +1 -0
- package/src/interface/ITextSetting.d.ts +25 -0
- package/src/interface/ITextSetting.js +1 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { execute as textFiledGetAlignOffsetService } from "../service/TextFiledGetAlignOffsetService";
|
|
2
|
+
import { execute as textFieldGenerateFontStyleService } from "../service/TextFieldGenerateFontStyleService";
|
|
3
|
+
import { $intToRGBA } from "../../RendererUtil";
|
|
4
|
+
/**
|
|
5
|
+
* @description TextDataを元にOffscreenCanvasにテキストを描画
|
|
6
|
+
* Draw text in OffscreenCanvas based on TextData
|
|
7
|
+
*
|
|
8
|
+
* @param {ITextData} text_data
|
|
9
|
+
* @param {object} text_setting
|
|
10
|
+
* @param {number} x_scale
|
|
11
|
+
* @param {number} y_scale
|
|
12
|
+
* @return {OffscreenCanvas}
|
|
13
|
+
* @method
|
|
14
|
+
* @protected
|
|
15
|
+
*/
|
|
16
|
+
export const execute = (text_data, text_setting, x_scale, y_scale) => {
|
|
17
|
+
const canvas = new OffscreenCanvas(text_setting.width, text_setting.height);
|
|
18
|
+
const context = canvas.getContext("2d");
|
|
19
|
+
if (!context) {
|
|
20
|
+
return canvas;
|
|
21
|
+
}
|
|
22
|
+
const lineWidth = Math.min(1, Math.max(x_scale, y_scale));
|
|
23
|
+
// border and background
|
|
24
|
+
if (text_setting.background || text_setting.border) {
|
|
25
|
+
context.beginPath();
|
|
26
|
+
context.moveTo(0, 0);
|
|
27
|
+
context.lineTo(text_setting.width, 0);
|
|
28
|
+
context.lineTo(text_setting.width, text_setting.height);
|
|
29
|
+
context.lineTo(0, text_setting.height);
|
|
30
|
+
context.lineTo(0, 0);
|
|
31
|
+
if (text_setting.background) {
|
|
32
|
+
const color = $intToRGBA(text_setting.backgroundColor);
|
|
33
|
+
context.fillStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
34
|
+
context.fill();
|
|
35
|
+
}
|
|
36
|
+
if (text_setting.border) {
|
|
37
|
+
const color = $intToRGBA(text_setting.borderColor);
|
|
38
|
+
context.lineWidth = lineWidth;
|
|
39
|
+
context.strokeStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
40
|
+
context.stroke();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!text_data) {
|
|
44
|
+
return canvas;
|
|
45
|
+
}
|
|
46
|
+
context.save();
|
|
47
|
+
context.beginPath();
|
|
48
|
+
context.moveTo(2, 2);
|
|
49
|
+
context.lineTo(text_setting.width - 2, 2);
|
|
50
|
+
context.lineTo(text_setting.width - 2, text_setting.height - 2);
|
|
51
|
+
context.lineTo(2, text_setting.height - 2);
|
|
52
|
+
context.lineTo(2, 2);
|
|
53
|
+
context.clip();
|
|
54
|
+
let tx = 2;
|
|
55
|
+
if (text_setting.scrollX > 0) {
|
|
56
|
+
const scaleX = (text_setting.textWidth + 4 - text_setting.rawWidth) / text_setting.rawWidth;
|
|
57
|
+
tx += -text_setting.scrollX * scaleX;
|
|
58
|
+
}
|
|
59
|
+
let ty = 2;
|
|
60
|
+
if (text_setting.scrollY > 0) {
|
|
61
|
+
const scaleY = (text_setting.textHeight + 2 - text_setting.rawHeight) / text_setting.rawHeight;
|
|
62
|
+
ty += -text_setting.scrollY * scaleY;
|
|
63
|
+
}
|
|
64
|
+
context.setTransform(x_scale, 0, 0, y_scale, tx * x_scale, ty * y_scale);
|
|
65
|
+
context.beginPath();
|
|
66
|
+
if (text_setting.selectIndex > -1
|
|
67
|
+
&& text_setting.focusIndex > -1) {
|
|
68
|
+
const range = text_data.textTable.length - 1;
|
|
69
|
+
let minIndex = 0;
|
|
70
|
+
let maxIndex = 0;
|
|
71
|
+
if (text_setting.focusIndex <= text_setting.selectIndex) {
|
|
72
|
+
minIndex = Math.min(text_setting.focusIndex, range);
|
|
73
|
+
maxIndex = Math.min(text_setting.selectIndex, range);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
minIndex = Math.min(text_setting.selectIndex, range);
|
|
77
|
+
maxIndex = Math.min(text_setting.focusIndex - 1, range);
|
|
78
|
+
}
|
|
79
|
+
const textObject = text_data.textTable[minIndex];
|
|
80
|
+
const lineObject = text_data.lineTable[textObject.line];
|
|
81
|
+
const offsetAlign = textFiledGetAlignOffsetService(text_data, lineObject, text_setting);
|
|
82
|
+
let x = 0;
|
|
83
|
+
if (minIndex && textObject.mode === "text") {
|
|
84
|
+
let idx = minIndex;
|
|
85
|
+
while (idx) {
|
|
86
|
+
const textObject = text_data.textTable[--idx];
|
|
87
|
+
if (textObject.mode !== "text") {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
x += textObject.w;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
context.fillStyle = "#b4d7ff";
|
|
94
|
+
let w = 0;
|
|
95
|
+
for (let idx = minIndex; idx <= maxIndex; ++idx) {
|
|
96
|
+
const textObject = text_data.textTable[idx];
|
|
97
|
+
if (textObject.mode === "text") {
|
|
98
|
+
w += textObject.w;
|
|
99
|
+
if (idx !== maxIndex) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
let y = 0;
|
|
104
|
+
const line = textObject.mode === "text"
|
|
105
|
+
? textObject.line
|
|
106
|
+
: textObject.line - 1;
|
|
107
|
+
for (let idx = 0; idx < line; ++idx) {
|
|
108
|
+
y += text_data.heightTable[idx];
|
|
109
|
+
}
|
|
110
|
+
context.beginPath();
|
|
111
|
+
context.rect(x, y, w + offsetAlign, text_data.heightTable[line]);
|
|
112
|
+
context.fill();
|
|
113
|
+
x = 0;
|
|
114
|
+
w = 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const rawWidth = text_setting.rawWidth;
|
|
118
|
+
let scrollX = 0;
|
|
119
|
+
if (text_setting.scrollX > 0) {
|
|
120
|
+
const scaleX = (text_setting.textWidth - rawWidth) / rawWidth;
|
|
121
|
+
scrollX = text_setting.scrollX * scaleX;
|
|
122
|
+
}
|
|
123
|
+
const limitWidth = rawWidth + scrollX;
|
|
124
|
+
const rawHeight = text_setting.rawHeight;
|
|
125
|
+
let scrollY = 0;
|
|
126
|
+
if (text_setting.scrollY > 0) {
|
|
127
|
+
const scaleY = (text_setting.textHeight - rawHeight) / rawHeight;
|
|
128
|
+
scrollY = text_setting.scrollY * scaleY;
|
|
129
|
+
}
|
|
130
|
+
const limitHeight = rawHeight + scrollY;
|
|
131
|
+
// setup
|
|
132
|
+
let offsetWidth = 0;
|
|
133
|
+
let offsetHeight = 0;
|
|
134
|
+
let offsetAlign = 0;
|
|
135
|
+
let verticalAlign = 0;
|
|
136
|
+
let skip = false;
|
|
137
|
+
let currentIndex = -1;
|
|
138
|
+
for (let idx = 0; idx < text_data.textTable.length; ++idx) {
|
|
139
|
+
const textObject = text_data.textTable[idx];
|
|
140
|
+
if (!textObject) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (textObject.mode === "text" || textObject.mode === "break") {
|
|
144
|
+
currentIndex++;
|
|
145
|
+
if (text_setting.stopIndex > -1
|
|
146
|
+
&& currentIndex > text_setting.stopIndex) {
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (skip && textObject.mode === "text") {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const textFormat = textObject.textFormat;
|
|
154
|
+
// check
|
|
155
|
+
if (text_setting.autoSize === "none") {
|
|
156
|
+
if (offsetHeight > limitHeight) {
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
if (textObject.mode === "text") {
|
|
160
|
+
if (scrollX > offsetWidth + textObject.w
|
|
161
|
+
|| offsetWidth > limitWidth) {
|
|
162
|
+
offsetWidth += textObject.w;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// color setting
|
|
168
|
+
const color = $intToRGBA(textFormat.color || 0);
|
|
169
|
+
context.fillStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
170
|
+
// focus line
|
|
171
|
+
if (text_setting.focusVisible
|
|
172
|
+
&& text_setting.focusIndex === idx) {
|
|
173
|
+
const x = offsetWidth + offsetAlign + 0.1;
|
|
174
|
+
let line = textObject.line;
|
|
175
|
+
let h = textObject.y;
|
|
176
|
+
let y = text_data.ascentTable[line];
|
|
177
|
+
if (textObject.mode !== "text") {
|
|
178
|
+
h = textObject.mode === "break"
|
|
179
|
+
? textObject.h
|
|
180
|
+
: text_data.ascentTable[line - 1];
|
|
181
|
+
if (line > 0) {
|
|
182
|
+
line = textObject.line - 1;
|
|
183
|
+
y = text_data.ascentTable[line];
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
y = textObject.h;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (line > 0 && text_data.ascentTable[line] === 0) {
|
|
190
|
+
line++;
|
|
191
|
+
}
|
|
192
|
+
for (let idx = 0; idx < line; ++idx) {
|
|
193
|
+
y += text_data.heightTable[idx];
|
|
194
|
+
}
|
|
195
|
+
context.strokeStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
196
|
+
context.beginPath();
|
|
197
|
+
context.moveTo(x, y);
|
|
198
|
+
context.lineTo(x, y - h);
|
|
199
|
+
context.stroke();
|
|
200
|
+
}
|
|
201
|
+
if (text_setting.thickness) {
|
|
202
|
+
const color = $intToRGBA(text_setting.thicknessColor);
|
|
203
|
+
context.lineWidth = text_setting.thickness;
|
|
204
|
+
context.strokeStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
205
|
+
}
|
|
206
|
+
const line = textObject.line | 0;
|
|
207
|
+
switch (textObject.mode) {
|
|
208
|
+
case "break":
|
|
209
|
+
case "wrap":
|
|
210
|
+
// reset width
|
|
211
|
+
offsetWidth = 0;
|
|
212
|
+
if (line) {
|
|
213
|
+
offsetHeight += text_data.heightTable[line - 1];
|
|
214
|
+
}
|
|
215
|
+
if (scrollY > offsetHeight + text_data.heightTable[line]) {
|
|
216
|
+
skip = true;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
verticalAlign = text_data.ascentTable[line];
|
|
220
|
+
offsetAlign = textFiledGetAlignOffsetService(text_data, textObject, text_setting);
|
|
221
|
+
skip = false;
|
|
222
|
+
break;
|
|
223
|
+
case "text":
|
|
224
|
+
{
|
|
225
|
+
context.beginPath();
|
|
226
|
+
context.font = textFieldGenerateFontStyleService(textFormat);
|
|
227
|
+
const x = offsetWidth + offsetAlign;
|
|
228
|
+
const y = offsetHeight + verticalAlign;
|
|
229
|
+
if (textFormat.underline) {
|
|
230
|
+
const color = $intToRGBA(textFormat.color || 0);
|
|
231
|
+
context.lineWidth = lineWidth;
|
|
232
|
+
context.strokeStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
233
|
+
context.beginPath();
|
|
234
|
+
context.moveTo(x, y + 2);
|
|
235
|
+
context.lineTo(x + textObject.w, y + 2);
|
|
236
|
+
context.stroke();
|
|
237
|
+
}
|
|
238
|
+
if (text_setting.thickness) {
|
|
239
|
+
context.strokeText(textObject.text, x, y);
|
|
240
|
+
}
|
|
241
|
+
context.fillText(textObject.text, x, y);
|
|
242
|
+
offsetWidth += textObject.w;
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
case "image":
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (text_setting.focusVisible
|
|
252
|
+
&& text_setting.focusIndex >= text_data.textTable.length) {
|
|
253
|
+
const textObject = text_data.textTable[text_setting.focusIndex - 1];
|
|
254
|
+
if (textObject) {
|
|
255
|
+
const color = $intToRGBA(textObject.textFormat.color || 0);
|
|
256
|
+
context.strokeStyle = `rgba(${color.R},${color.G},${color.B},${color.A})`;
|
|
257
|
+
const x = offsetWidth + offsetAlign + 0.1;
|
|
258
|
+
const y = offsetHeight + verticalAlign;
|
|
259
|
+
context.beginPath();
|
|
260
|
+
if (textObject.mode === "text") {
|
|
261
|
+
context.moveTo(x, y - textObject.y);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
context.moveTo(x, y + textObject.h);
|
|
265
|
+
}
|
|
266
|
+
context.lineTo(x, y);
|
|
267
|
+
context.stroke();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
context.restore();
|
|
271
|
+
return canvas;
|
|
272
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description TextFieldの描画を実行します。
|
|
3
|
+
* Execute the drawing of TextField.
|
|
4
|
+
*
|
|
5
|
+
* @param {Float32Array} render_queue
|
|
6
|
+
* @param {number} index
|
|
7
|
+
* @return {number}
|
|
8
|
+
* @method
|
|
9
|
+
* @protected
|
|
10
|
+
*/
|
|
11
|
+
export declare const execute: (render_queue: Float32Array, index: number) => number;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { $cacheStore } from "@next2d/cache";
|
|
2
|
+
import { execute as displayObjectGetBlendModeService } from "../../DisplayObject/service/DisplayObjectGetBlendModeService";
|
|
3
|
+
import { execute as textFieldDrawOffscreenCanvasUseCase } from "./TextFieldDrawOffscreenCanvasUseCase";
|
|
4
|
+
import { $context } from "../../RendererUtil";
|
|
5
|
+
/**
|
|
6
|
+
* @type {TextDecoder}
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
const $textDecoder = new TextDecoder();
|
|
10
|
+
/**
|
|
11
|
+
* @description TextFieldの描画を実行します。
|
|
12
|
+
* Execute the drawing of TextField.
|
|
13
|
+
*
|
|
14
|
+
* @param {Float32Array} render_queue
|
|
15
|
+
* @param {number} index
|
|
16
|
+
* @return {number}
|
|
17
|
+
* @method
|
|
18
|
+
* @protected
|
|
19
|
+
*/
|
|
20
|
+
export const execute = (render_queue, index) => {
|
|
21
|
+
const matrix = render_queue.subarray(index, index + 6);
|
|
22
|
+
index += 6;
|
|
23
|
+
const colorTransform = render_queue.subarray(index, index + 8);
|
|
24
|
+
index += 8;
|
|
25
|
+
const bounds = render_queue.subarray(index, index + 4);
|
|
26
|
+
index += 4;
|
|
27
|
+
// baseBounds
|
|
28
|
+
const xMin = render_queue[index++];
|
|
29
|
+
const yMin = render_queue[index++];
|
|
30
|
+
const xMax = render_queue[index++];
|
|
31
|
+
const yMax = render_queue[index++];
|
|
32
|
+
// cache uniqueKey
|
|
33
|
+
const uniqueKey = `${render_queue[index++]}`;
|
|
34
|
+
const cacheKey = render_queue[index++];
|
|
35
|
+
// text state
|
|
36
|
+
const changed = Boolean(render_queue[index++]);
|
|
37
|
+
const xScale = Math.round(Math.sqrt(matrix[0] * matrix[0]
|
|
38
|
+
+ matrix[1] * matrix[1]) * 10000) / 10000;
|
|
39
|
+
const yScale = Math.round(Math.sqrt(matrix[2] * matrix[2]
|
|
40
|
+
+ matrix[3] * matrix[3]) * 10000) / 10000;
|
|
41
|
+
let node;
|
|
42
|
+
const hasCache = render_queue[index++];
|
|
43
|
+
if (!hasCache) {
|
|
44
|
+
const width = Math.ceil(Math.abs(xMax - xMin) * xScale);
|
|
45
|
+
const height = Math.ceil(Math.abs(yMax - yMin) * yScale);
|
|
46
|
+
const hasNode = Boolean(render_queue[index++]);
|
|
47
|
+
node = hasNode
|
|
48
|
+
? $cacheStore.get(uniqueKey, `${cacheKey}`)
|
|
49
|
+
: $context.createNode(width, height);
|
|
50
|
+
if (!hasNode) {
|
|
51
|
+
$cacheStore.set(uniqueKey, `${cacheKey}`, node);
|
|
52
|
+
}
|
|
53
|
+
const length = render_queue[index++];
|
|
54
|
+
const buffer = new Uint8Array(render_queue.subarray(index, index + length));
|
|
55
|
+
index += length;
|
|
56
|
+
let autoSize = "none";
|
|
57
|
+
switch (render_queue[index++]) {
|
|
58
|
+
case 0:
|
|
59
|
+
autoSize = "center";
|
|
60
|
+
break;
|
|
61
|
+
case 1:
|
|
62
|
+
autoSize = "left";
|
|
63
|
+
break;
|
|
64
|
+
case 2:
|
|
65
|
+
autoSize = "none";
|
|
66
|
+
break;
|
|
67
|
+
case 3:
|
|
68
|
+
autoSize = "right";
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
const textSetting = {
|
|
72
|
+
"width": width,
|
|
73
|
+
"height": height,
|
|
74
|
+
"autoSize": autoSize,
|
|
75
|
+
"stopIndex": render_queue[index++],
|
|
76
|
+
"scrollX": render_queue[index++],
|
|
77
|
+
"scrollY": render_queue[index++],
|
|
78
|
+
"textWidth": render_queue[index++],
|
|
79
|
+
"textHeight": render_queue[index++],
|
|
80
|
+
"rawWidth": render_queue[index++],
|
|
81
|
+
"rawHeight": render_queue[index++],
|
|
82
|
+
"focusIndex": render_queue[index++],
|
|
83
|
+
"selectIndex": render_queue[index++],
|
|
84
|
+
"focusVisible": Boolean(render_queue[index++]),
|
|
85
|
+
"thickness": render_queue[index++],
|
|
86
|
+
"thicknessColor": render_queue[index++],
|
|
87
|
+
"wordWrap": Boolean(render_queue[index++]),
|
|
88
|
+
"border": Boolean(render_queue[index++]),
|
|
89
|
+
"borderColor": render_queue[index++],
|
|
90
|
+
"background": Boolean(render_queue[index++]),
|
|
91
|
+
"backgroundColor": render_queue[index++],
|
|
92
|
+
"defaultColor": render_queue[index++],
|
|
93
|
+
"defaultSize": render_queue[index++]
|
|
94
|
+
};
|
|
95
|
+
const canvas = textFieldDrawOffscreenCanvasUseCase(JSON.parse($textDecoder.decode(buffer)), textSetting, xScale, yScale);
|
|
96
|
+
// fixed logic
|
|
97
|
+
const currentAttachment = $context.currentAttachmentObject;
|
|
98
|
+
$context.bind($context.atlasAttachmentObject);
|
|
99
|
+
$context.reset();
|
|
100
|
+
$context.beginNodeRendering(node);
|
|
101
|
+
const offsetY = $context.atlasAttachmentObject.height - node.y - height;
|
|
102
|
+
$context.setTransform(1, 0, 0, 1, node.x, offsetY);
|
|
103
|
+
$context.drawElement(node, canvas);
|
|
104
|
+
$context.endNodeRendering();
|
|
105
|
+
if (currentAttachment) {
|
|
106
|
+
$context.bind(currentAttachment);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
node = $cacheStore.get(uniqueKey, `${cacheKey}`);
|
|
111
|
+
if (!node) {
|
|
112
|
+
return index;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const blendMode = render_queue[index++];
|
|
116
|
+
// フィルター設定があればフィルターを実行
|
|
117
|
+
const useFilfer = Boolean(render_queue[index++]);
|
|
118
|
+
if (useFilfer) {
|
|
119
|
+
const updated = Boolean(render_queue[index++]);
|
|
120
|
+
const filterBounds = render_queue.subarray(index, index + 4);
|
|
121
|
+
index += 4;
|
|
122
|
+
const length = render_queue[index++];
|
|
123
|
+
const params = render_queue.subarray(index, index + length);
|
|
124
|
+
const width = Math.ceil(Math.abs(bounds[2] - bounds[0]));
|
|
125
|
+
const height = Math.ceil(Math.abs(bounds[3] - bounds[1]));
|
|
126
|
+
$context.applyFilter(node, uniqueKey, Boolean(Math.max(+changed, +updated)), width, height, false, matrix, colorTransform, displayObjectGetBlendModeService(blendMode), filterBounds, params);
|
|
127
|
+
index += length;
|
|
128
|
+
return index;
|
|
129
|
+
}
|
|
130
|
+
$context.globalAlpha = Math.min(Math.max(0, colorTransform[3] + colorTransform[7] / 255), 1);
|
|
131
|
+
$context.imageSmoothingEnabled = true;
|
|
132
|
+
$context.globalCompositeOperation = displayObjectGetBlendModeService(blendMode);
|
|
133
|
+
const radianX = Math.atan2(matrix[1], matrix[0]);
|
|
134
|
+
const radianY = Math.atan2(-matrix[2], matrix[3]);
|
|
135
|
+
if (radianX || radianY) {
|
|
136
|
+
const tx = xMin * xScale;
|
|
137
|
+
const ty = yMin * yScale;
|
|
138
|
+
const cosX = Math.cos(radianX);
|
|
139
|
+
const sinX = Math.sin(radianX);
|
|
140
|
+
const cosY = Math.cos(radianY);
|
|
141
|
+
const sinY = Math.sin(radianY);
|
|
142
|
+
$context.setTransform(cosX, sinX, -sinY, cosY, tx * cosX - ty * sinY + matrix[4], tx * sinX + ty * cosY + matrix[5]);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
$context.setTransform(1, 0, 0, 1, bounds[0], bounds[1]);
|
|
146
|
+
}
|
|
147
|
+
// 描画範囲をinstanced arrayに設定
|
|
148
|
+
$context.drawDisplayObject(node, bounds[0], bounds[1], bounds[2], bounds[3], colorTransform);
|
|
149
|
+
return index;
|
|
150
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Videoの描画を実行します。
|
|
3
|
+
* Execute the drawing of Video.
|
|
4
|
+
*
|
|
5
|
+
* @param {Float32Array} render_queue
|
|
6
|
+
* @param {number} index
|
|
7
|
+
* @param {ImageBitmap[]} image_bitmaps
|
|
8
|
+
* @return {number}
|
|
9
|
+
* @method
|
|
10
|
+
* @protected
|
|
11
|
+
*/
|
|
12
|
+
export declare const execute: (render_queue: Float32Array, index: number, image_bitmaps: ImageBitmap[] | null) => number;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { $cacheStore } from "@next2d/cache";
|
|
2
|
+
import { $context } from "../../RendererUtil";
|
|
3
|
+
import { execute as displayObjectGetBlendModeService } from "../../DisplayObject/service/DisplayObjectGetBlendModeService";
|
|
4
|
+
/**
|
|
5
|
+
* @description Videoの描画を実行します。
|
|
6
|
+
* Execute the drawing of Video.
|
|
7
|
+
*
|
|
8
|
+
* @param {Float32Array} render_queue
|
|
9
|
+
* @param {number} index
|
|
10
|
+
* @param {ImageBitmap[]} image_bitmaps
|
|
11
|
+
* @return {number}
|
|
12
|
+
* @method
|
|
13
|
+
* @protected
|
|
14
|
+
*/
|
|
15
|
+
export const execute = (render_queue, index, image_bitmaps) => {
|
|
16
|
+
const matrix = render_queue.subarray(index, index + 6);
|
|
17
|
+
index += 6;
|
|
18
|
+
const colorTransform = render_queue.subarray(index, index + 8);
|
|
19
|
+
index += 8;
|
|
20
|
+
const bounds = render_queue.subarray(index, index + 4);
|
|
21
|
+
index += 4;
|
|
22
|
+
// baseBounds
|
|
23
|
+
const xMin = render_queue[index++];
|
|
24
|
+
const yMin = render_queue[index++];
|
|
25
|
+
const xMax = render_queue[index++];
|
|
26
|
+
const yMax = render_queue[index++];
|
|
27
|
+
// cache uniqueKey
|
|
28
|
+
const uniqueKey = `${render_queue[index++]}`;
|
|
29
|
+
const cacheKey = "0";
|
|
30
|
+
// video state
|
|
31
|
+
const changed = Boolean(render_queue[index++]);
|
|
32
|
+
let node;
|
|
33
|
+
const hasCache = render_queue[index++];
|
|
34
|
+
if (!hasCache) {
|
|
35
|
+
const width = Math.abs(xMax - xMin);
|
|
36
|
+
const height = Math.abs(yMax - yMin);
|
|
37
|
+
const hasNode = Boolean(render_queue[index++]);
|
|
38
|
+
node = hasNode
|
|
39
|
+
? $cacheStore.get(uniqueKey, `${cacheKey}`)
|
|
40
|
+
: $context.createNode(width, height);
|
|
41
|
+
if (!hasNode) {
|
|
42
|
+
$cacheStore.set(uniqueKey, `${cacheKey}`, node);
|
|
43
|
+
}
|
|
44
|
+
if (image_bitmaps && image_bitmaps.length) {
|
|
45
|
+
// fixed logic
|
|
46
|
+
const currentAttachment = $context.currentAttachmentObject;
|
|
47
|
+
$context.bind($context.atlasAttachmentObject);
|
|
48
|
+
$context.reset();
|
|
49
|
+
$context.beginNodeRendering(node);
|
|
50
|
+
const offsetY = $context.atlasAttachmentObject.height - node.y - height;
|
|
51
|
+
$context.setTransform(1, 0, 0, 1, node.x, offsetY);
|
|
52
|
+
const imageBitmap = image_bitmaps.shift();
|
|
53
|
+
$context.drawElement(node, imageBitmap);
|
|
54
|
+
$context.endNodeRendering();
|
|
55
|
+
if (currentAttachment) {
|
|
56
|
+
$context.bind(currentAttachment);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
node = $cacheStore.get(uniqueKey, `${cacheKey}`);
|
|
62
|
+
if (!node) {
|
|
63
|
+
return index;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const blendMode = render_queue[index++];
|
|
67
|
+
// フィルター設定があればフィルターを実行
|
|
68
|
+
const useFilfer = Boolean(render_queue[index++]);
|
|
69
|
+
if (useFilfer) {
|
|
70
|
+
const updated = Boolean(render_queue[index++]);
|
|
71
|
+
const filterBounds = render_queue.subarray(index, index + 4);
|
|
72
|
+
index += 4;
|
|
73
|
+
const length = render_queue[index++];
|
|
74
|
+
const params = render_queue.subarray(index, index + length);
|
|
75
|
+
const width = Math.ceil(Math.abs(bounds[2] - bounds[0]));
|
|
76
|
+
const height = Math.ceil(Math.abs(bounds[3] - bounds[1]));
|
|
77
|
+
$context.applyFilter(node, uniqueKey, Boolean(Math.max(+changed, +updated)), width, height, true, matrix, colorTransform, displayObjectGetBlendModeService(blendMode), filterBounds, params);
|
|
78
|
+
index += length;
|
|
79
|
+
return index;
|
|
80
|
+
}
|
|
81
|
+
$context.globalAlpha = Math.min(Math.max(0, colorTransform[3] + colorTransform[7] / 255), 1);
|
|
82
|
+
$context.imageSmoothingEnabled = true;
|
|
83
|
+
$context.globalCompositeOperation = displayObjectGetBlendModeService(blendMode);
|
|
84
|
+
$context.setTransform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
|
|
85
|
+
// 描画範囲をinstanced arrayに設定
|
|
86
|
+
$context.drawDisplayObject(node, bounds[0], bounds[1], bounds[2], bounds[3], colorTransform);
|
|
87
|
+
return index;
|
|
88
|
+
};
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { CommandController } from "./CommandController";
|
|
3
|
+
/**
|
|
4
|
+
* @description CommandControllerのインスタンス
|
|
5
|
+
* Instance of CommandController
|
|
6
|
+
*
|
|
7
|
+
* @type {CommandController}
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
const command = new CommandController();
|
|
11
|
+
/**
|
|
12
|
+
* @description OffscreenCanvasのメッセージイベント
|
|
13
|
+
* OffscreenCanvas message event
|
|
14
|
+
*
|
|
15
|
+
* @params {MessageEvent} event
|
|
16
|
+
* @return {Promise<void>}
|
|
17
|
+
* @method
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
self.addEventListener("message", async (event) => {
|
|
21
|
+
command.queue.push(event.data);
|
|
22
|
+
if (command.state === "deactivate") {
|
|
23
|
+
await command.execute();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
export default {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type IBlendMode = "copy" | "add" | "alpha" | "darken" | "difference" | "erase" | "hardlight" | "invert" | "layer" | "lighten" | "multiply" | "normal" | "overlay" | "screen" | "subtract";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ITextFieldAutoSize = "center" | "left" | "none" | "right";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ITextFormatAlign } from "./ITextFormatAlign";
|
|
2
|
+
export interface ITextFormat {
|
|
3
|
+
align: ITextFormatAlign | null;
|
|
4
|
+
bold: boolean | null;
|
|
5
|
+
color: number | null;
|
|
6
|
+
font: string | null;
|
|
7
|
+
italic: boolean | null;
|
|
8
|
+
leading: number | null;
|
|
9
|
+
leftMargin: number | null;
|
|
10
|
+
letterSpacing: number | null;
|
|
11
|
+
rightMargin: number | null;
|
|
12
|
+
size: number | null;
|
|
13
|
+
underline: boolean | null;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ITextFormatAlign = "center" | "left" | "right";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITextFormat } from "./ITextFormat";
|
|
2
|
+
import type { ITextObjectMode } from "./ITextObjectMode";
|
|
3
|
+
export interface ITextObject {
|
|
4
|
+
mode: ITextObjectMode;
|
|
5
|
+
text: string;
|
|
6
|
+
textFormat: ITextFormat;
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
w: number;
|
|
10
|
+
h: number;
|
|
11
|
+
line: number;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ITextObjectMode = "break" | "wrap" | "image" | "text";
|