@tutti-os/workbench-surface 0.0.224 → 0.0.225
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/dist/index.js +108 -27
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3820,17 +3820,40 @@ function renderGenieScanlines(context, viewportWidth, viewportHeight, frame) {
|
|
|
3820
3820
|
}
|
|
3821
3821
|
|
|
3822
3822
|
// src/react/genieTextureCapture.ts
|
|
3823
|
+
var readableStylesheetTextByDocument = /* @__PURE__ */ new WeakMap();
|
|
3824
|
+
function hasSameStylesheetFingerprints(left, right) {
|
|
3825
|
+
return left.length === right.length && left.every((fingerprint, index) => {
|
|
3826
|
+
const candidate = right[index];
|
|
3827
|
+
return candidate?.stylesheet === fingerprint.stylesheet && candidate.disabled === fingerprint.disabled && candidate.ruleCount === fingerprint.ruleCount && candidate.ownerText === fingerprint.ownerText;
|
|
3828
|
+
});
|
|
3829
|
+
}
|
|
3823
3830
|
function collectReadableStylesheetText(document2) {
|
|
3824
|
-
const
|
|
3831
|
+
const readableStylesheets = [];
|
|
3825
3832
|
for (const stylesheet of Array.from(document2.styleSheets)) {
|
|
3826
3833
|
try {
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3834
|
+
const rules = stylesheet.cssRules;
|
|
3835
|
+
readableStylesheets.push({
|
|
3836
|
+
fingerprint: {
|
|
3837
|
+
disabled: stylesheet.disabled,
|
|
3838
|
+
ownerText: stylesheet.ownerNode instanceof HTMLStyleElement ? stylesheet.ownerNode.textContent : null,
|
|
3839
|
+
ruleCount: rules.length,
|
|
3840
|
+
stylesheet
|
|
3841
|
+
},
|
|
3842
|
+
rules
|
|
3843
|
+
});
|
|
3830
3844
|
} catch {
|
|
3831
3845
|
}
|
|
3832
3846
|
}
|
|
3833
|
-
|
|
3847
|
+
const fingerprints = readableStylesheets.map(
|
|
3848
|
+
({ fingerprint }) => fingerprint
|
|
3849
|
+
);
|
|
3850
|
+
const cached = readableStylesheetTextByDocument.get(document2);
|
|
3851
|
+
if (cached && hasSameStylesheetFingerprints(cached.fingerprints, fingerprints)) {
|
|
3852
|
+
return cached.text;
|
|
3853
|
+
}
|
|
3854
|
+
const text = readableStylesheets.flatMap(({ rules }) => Array.from(rules, (rule) => rule.cssText)).join("\n");
|
|
3855
|
+
readableStylesheetTextByDocument.set(document2, { fingerprints, text });
|
|
3856
|
+
return text;
|
|
3834
3857
|
}
|
|
3835
3858
|
function collectImageClones(element) {
|
|
3836
3859
|
return Array.from(element.querySelectorAll("img")).map((image) => {
|
|
@@ -3838,6 +3861,8 @@ function collectImageClones(element) {
|
|
|
3838
3861
|
return {
|
|
3839
3862
|
displayHeight: rect.height,
|
|
3840
3863
|
displayWidth: rect.width,
|
|
3864
|
+
naturalHeight: image.naturalHeight,
|
|
3865
|
+
naturalWidth: image.naturalWidth,
|
|
3841
3866
|
url: image.currentSrc || image.src || image.getAttribute("src") || null
|
|
3842
3867
|
};
|
|
3843
3868
|
});
|
|
@@ -3936,10 +3961,12 @@ var dockPreviewMaxWidth = 260;
|
|
|
3936
3961
|
var dockPreviewMaxHeight = 170;
|
|
3937
3962
|
var dockPreviewImageCacheMaxEntries = 96;
|
|
3938
3963
|
var inlineImageResourceCacheMaxEntries = 160;
|
|
3964
|
+
var inlineImageResizeTargetCacheMaxEntries = 4;
|
|
3939
3965
|
var dockAnchorFallbackSizePx = 43.2;
|
|
3940
3966
|
var genieInlineImageMaxDevicePixelRatio = 2;
|
|
3941
3967
|
var dockPreviewImageByNodeID = /* @__PURE__ */ new Map();
|
|
3942
3968
|
var inlineImageResourceByUrl = /* @__PURE__ */ new Map();
|
|
3969
|
+
var resizedInlineImageResourceByUrl = /* @__PURE__ */ new Map();
|
|
3943
3970
|
function resolveWorkbenchCaptureElement(windowElement) {
|
|
3944
3971
|
return windowElement.querySelector(
|
|
3945
3972
|
'[data-workbench-window-capture="true"]'
|
|
@@ -4080,7 +4107,8 @@ async function inlineCloneImageResources({
|
|
|
4080
4107
|
return;
|
|
4081
4108
|
}
|
|
4082
4109
|
const inlineImageUrl = await readInlineImageResource(imageUrl) ?? imageUrl;
|
|
4083
|
-
const resizedImageUrl = await
|
|
4110
|
+
const resizedImageUrl = await readResizedInlineImageResource(
|
|
4111
|
+
imageUrl,
|
|
4084
4112
|
inlineImageUrl,
|
|
4085
4113
|
imageInfo
|
|
4086
4114
|
);
|
|
@@ -4114,11 +4142,7 @@ function resolveGenieInlineImageTargetSize({
|
|
|
4114
4142
|
width: Math.max(1, Math.ceil(displayWidth * scale))
|
|
4115
4143
|
};
|
|
4116
4144
|
}
|
|
4117
|
-
async function resizeInlineImageResourceForGenieTexture(imageUrl,
|
|
4118
|
-
const targetSize = resolveGenieInlineImageTargetSize(imageInfo);
|
|
4119
|
-
if (!targetSize) {
|
|
4120
|
-
return null;
|
|
4121
|
-
}
|
|
4145
|
+
async function resizeInlineImageResourceForGenieTexture(imageUrl, targetSize) {
|
|
4122
4146
|
const image = new Image();
|
|
4123
4147
|
image.src = imageUrl;
|
|
4124
4148
|
try {
|
|
@@ -4143,6 +4167,50 @@ async function resizeInlineImageResourceForGenieTexture(imageUrl, imageInfo) {
|
|
|
4143
4167
|
return null;
|
|
4144
4168
|
}
|
|
4145
4169
|
}
|
|
4170
|
+
function readResizedInlineImageResource(sourceImageUrl, inlineImageUrl, imageInfo) {
|
|
4171
|
+
const targetSize = resolveGenieInlineImageTargetSize(imageInfo);
|
|
4172
|
+
if (!targetSize) {
|
|
4173
|
+
return Promise.resolve(null);
|
|
4174
|
+
}
|
|
4175
|
+
if (imageInfo.naturalWidth > 0 && imageInfo.naturalHeight > 0 && imageInfo.naturalWidth <= targetSize.width && imageInfo.naturalHeight <= targetSize.height) {
|
|
4176
|
+
return Promise.resolve(null);
|
|
4177
|
+
}
|
|
4178
|
+
let resizedByTarget = resizedInlineImageResourceByUrl.get(sourceImageUrl);
|
|
4179
|
+
if (resizedByTarget) {
|
|
4180
|
+
resizedInlineImageResourceByUrl.delete(sourceImageUrl);
|
|
4181
|
+
resizedInlineImageResourceByUrl.set(sourceImageUrl, resizedByTarget);
|
|
4182
|
+
} else {
|
|
4183
|
+
resizedByTarget = /* @__PURE__ */ new Map();
|
|
4184
|
+
resizedInlineImageResourceByUrl.set(sourceImageUrl, resizedByTarget);
|
|
4185
|
+
}
|
|
4186
|
+
const targetKey = `${targetSize.width}x${targetSize.height}`;
|
|
4187
|
+
const cached = resizedByTarget.get(targetKey);
|
|
4188
|
+
if (cached) {
|
|
4189
|
+
resizedByTarget.delete(targetKey);
|
|
4190
|
+
resizedByTarget.set(targetKey, cached);
|
|
4191
|
+
return cached;
|
|
4192
|
+
}
|
|
4193
|
+
const promise = resizeInlineImageResourceForGenieTexture(
|
|
4194
|
+
inlineImageUrl,
|
|
4195
|
+
targetSize
|
|
4196
|
+
);
|
|
4197
|
+
resizedByTarget.set(targetKey, promise);
|
|
4198
|
+
while (resizedByTarget.size > inlineImageResizeTargetCacheMaxEntries) {
|
|
4199
|
+
const oldestTarget = resizedByTarget.keys().next().value;
|
|
4200
|
+
if (typeof oldestTarget !== "string") {
|
|
4201
|
+
break;
|
|
4202
|
+
}
|
|
4203
|
+
resizedByTarget.delete(oldestTarget);
|
|
4204
|
+
}
|
|
4205
|
+
while (resizedInlineImageResourceByUrl.size > inlineImageResourceCacheMaxEntries) {
|
|
4206
|
+
const oldestImageUrl = resizedInlineImageResourceByUrl.keys().next().value;
|
|
4207
|
+
if (typeof oldestImageUrl !== "string") {
|
|
4208
|
+
break;
|
|
4209
|
+
}
|
|
4210
|
+
resizedInlineImageResourceByUrl.delete(oldestImageUrl);
|
|
4211
|
+
}
|
|
4212
|
+
return promise;
|
|
4213
|
+
}
|
|
4146
4214
|
function prepareRenderedGeniePreviewCloneForTexture(clone, textureRect) {
|
|
4147
4215
|
clone.style.width = `${textureRect.width}px`;
|
|
4148
4216
|
clone.style.height = `${textureRect.height}px`;
|
|
@@ -4162,20 +4230,24 @@ function prepareRenderedGeniePreviewCloneForTexture(clone, textureRect) {
|
|
|
4162
4230
|
previewElement.style.boxShadow = "none";
|
|
4163
4231
|
previewElement.style.transform = `translateY(${renderedGeniePreviewHeaderOffsetPx}px)`;
|
|
4164
4232
|
}
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4233
|
+
function resolveGenieTextureOutputSize(rect, limits) {
|
|
4234
|
+
const scale = limits ? Math.min(1, limits.maxWidth / rect.width, limits.maxHeight / rect.height) : genieSnapshotScale;
|
|
4235
|
+
return {
|
|
4236
|
+
height: Math.max(1, Math.round(rect.height * scale)),
|
|
4237
|
+
width: Math.max(1, Math.round(rect.width * scale))
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
async function renderPreparedElementTexture({ clone, images, rect }, outputLimits) {
|
|
4170
4241
|
await inlineCloneImageResources({
|
|
4171
4242
|
cloneRoot: clone,
|
|
4172
4243
|
images
|
|
4173
4244
|
});
|
|
4174
|
-
const
|
|
4245
|
+
const outputSize = resolveGenieTextureOutputSize(rect, outputLimits);
|
|
4246
|
+
const svgTexture = createGenieSvgTexture(clone, rect, outputSize);
|
|
4175
4247
|
const image = await loadImageFromSvg(svgTexture);
|
|
4176
4248
|
const canvas = document.createElement("canvas");
|
|
4177
|
-
canvas.width =
|
|
4178
|
-
canvas.height =
|
|
4249
|
+
canvas.width = outputSize.width;
|
|
4250
|
+
canvas.height = outputSize.height;
|
|
4179
4251
|
const context = canvas.getContext("2d");
|
|
4180
4252
|
if (!context) {
|
|
4181
4253
|
return null;
|
|
@@ -4185,9 +4257,9 @@ async function renderPreparedElementTexture({
|
|
|
4185
4257
|
context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
4186
4258
|
return { canvas, rect };
|
|
4187
4259
|
}
|
|
4188
|
-
async function captureElementTexture(element) {
|
|
4260
|
+
async function captureElementTexture(element, outputLimits) {
|
|
4189
4261
|
const preparedCapture = prepareGenieTextureCapture(element);
|
|
4190
|
-
return preparedCapture ? renderPreparedElementTexture(preparedCapture) : null;
|
|
4262
|
+
return preparedCapture ? renderPreparedElementTexture(preparedCapture, outputLimits) : null;
|
|
4191
4263
|
}
|
|
4192
4264
|
function createDockPreviewDataUrl(canvas) {
|
|
4193
4265
|
if (canvas.width <= 0 || canvas.height <= 0) {
|
|
@@ -4198,6 +4270,9 @@ function createDockPreviewDataUrl(canvas) {
|
|
|
4198
4270
|
dockPreviewMaxWidth / canvas.width,
|
|
4199
4271
|
dockPreviewMaxHeight / canvas.height
|
|
4200
4272
|
);
|
|
4273
|
+
if (scale === 1) {
|
|
4274
|
+
return canvas.toDataURL("image/png");
|
|
4275
|
+
}
|
|
4201
4276
|
const output = document.createElement("canvas");
|
|
4202
4277
|
output.width = Math.max(1, Math.round(canvas.width * scale));
|
|
4203
4278
|
output.height = Math.max(1, Math.round(canvas.height * scale));
|
|
@@ -4282,7 +4357,10 @@ async function captureWorkbenchNodePreviewImage(nodeID, options = {}) {
|
|
|
4282
4357
|
if (!captureTarget) {
|
|
4283
4358
|
return null;
|
|
4284
4359
|
}
|
|
4285
|
-
const texture = await captureElementTexture(captureTarget
|
|
4360
|
+
const texture = await captureElementTexture(captureTarget, {
|
|
4361
|
+
maxHeight: dockPreviewMaxHeight,
|
|
4362
|
+
maxWidth: dockPreviewMaxWidth
|
|
4363
|
+
}).catch(() => null);
|
|
4286
4364
|
const previewImageUrl = texture ? createDockPreviewDataUrl(texture.canvas) : null;
|
|
4287
4365
|
writeCachedWorkbenchNodePreviewImage(nodeID, previewImageUrl);
|
|
4288
4366
|
return previewImageUrl;
|
|
@@ -4308,7 +4386,10 @@ function persistWorkbenchNodePreviewImage(node, previewImageUrl, input) {
|
|
|
4308
4386
|
}
|
|
4309
4387
|
input.dockPreviewCache.write({ key, previewImageUrl });
|
|
4310
4388
|
}
|
|
4311
|
-
function createGenieSvgTexture(element, rect
|
|
4389
|
+
function createGenieSvgTexture(element, rect, outputSize = {
|
|
4390
|
+
height: rect.height,
|
|
4391
|
+
width: rect.width
|
|
4392
|
+
}) {
|
|
4312
4393
|
const svgNamespace = "http://www.w3.org/2000/svg";
|
|
4313
4394
|
const svgDocument = document.implementation.createDocument(
|
|
4314
4395
|
svgNamespace,
|
|
@@ -4317,15 +4398,15 @@ function createGenieSvgTexture(element, rect) {
|
|
|
4317
4398
|
);
|
|
4318
4399
|
const svg = svgDocument.documentElement;
|
|
4319
4400
|
svg.setAttribute("xmlns", svgNamespace);
|
|
4320
|
-
svg.setAttribute("width", String(
|
|
4321
|
-
svg.setAttribute("height", String(
|
|
4401
|
+
svg.setAttribute("width", String(outputSize.width));
|
|
4402
|
+
svg.setAttribute("height", String(outputSize.height));
|
|
4322
4403
|
svg.setAttribute("viewBox", `0 0 ${rect.width} ${rect.height}`);
|
|
4323
4404
|
const foreignObject = svgDocument.createElementNS(
|
|
4324
4405
|
svgNamespace,
|
|
4325
4406
|
"foreignObject"
|
|
4326
4407
|
);
|
|
4327
|
-
foreignObject.setAttribute("width",
|
|
4328
|
-
foreignObject.setAttribute("height",
|
|
4408
|
+
foreignObject.setAttribute("width", String(rect.width));
|
|
4409
|
+
foreignObject.setAttribute("height", String(rect.height));
|
|
4329
4410
|
foreignObject.setAttribute("x", "0");
|
|
4330
4411
|
foreignObject.setAttribute("y", "0");
|
|
4331
4412
|
foreignObject.appendChild(svgDocument.importNode(element, true));
|