domotion-svg 0.7.0 → 0.8.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/dist/capture/script/walker/pseudo-content.js +13 -2
- package/dist/capture/script/walker/text-segments.js +60 -29
- package/dist/capture/script.generated.js +1 -1
- package/dist/render/element-tree-to-svg.js +13 -1
- package/dist/render/text-to-path.js +35 -6
- package/dist/review/client.bundle.generated.js +1 -1
- package/dist/review/client.js +56 -15
- package/dist/review/server.js +12 -4
- package/package.json +2 -1
|
@@ -159,8 +159,19 @@ export const createPseudoContentHandler = ({ vp, normColor, measureFontMetrics,
|
|
|
159
159
|
probe.style.marginRight = pcs.marginRight;
|
|
160
160
|
probe.style.marginBottom = pcs.marginBottom;
|
|
161
161
|
probe.style.marginLeft = pcs.marginLeft;
|
|
162
|
-
|
|
163
|
-
probe.
|
|
162
|
+
// DM-928: deliberately DO NOT apply the pseudo's `transform` to the
|
|
163
|
+
// probe. CSS transforms only affect paint, not layout; the probe's
|
|
164
|
+
// `getBoundingClientRect()` returns the AXIS-ALIGNED bounding box of
|
|
165
|
+
// whatever box it currently paints. With a 45° rotation, that AABB is
|
|
166
|
+
// ~√2 × larger than the actual border-box and its top-left sits
|
|
167
|
+
// ~(diagonal-extra)/2 to the upper-left of the true border-box origin
|
|
168
|
+
// — re-rotating that AABB later via the `<g transform>` wrapper
|
|
169
|
+
// places the painted strokes at the wrong position (pricing-table
|
|
170
|
+
// checkmarks drift ~4 px left / 1 px up). Strip the transform here
|
|
171
|
+
// and let the unrotated probe report the actual border-box rect; the
|
|
172
|
+
// transform is re-applied at render time inside `flushPbTransformWrap`.
|
|
173
|
+
probe.style.transform = '';
|
|
174
|
+
probe.style.transformOrigin = '';
|
|
164
175
|
// Pseudo lives logically inside the host; an absolute child of the host
|
|
165
176
|
// inherits the same containing-block lookup.
|
|
166
177
|
if (pseudo === '::before')
|
|
@@ -414,39 +414,70 @@ export const createTextSegmentsHandler = ({ vp, measureFontMetrics, needsRaster
|
|
|
414
414
|
let rasterLeft = cRec.left - vp.x;
|
|
415
415
|
let rasterWidth = cRec.right - cRec.left;
|
|
416
416
|
if (isFirstLetter) {
|
|
417
|
-
const
|
|
418
|
-
const ilN = parseFloat(ilRaw);
|
|
419
|
-
const parentLineHeight = parseFloat(cs.lineHeight);
|
|
420
|
-
if (Number.isFinite(ilN) && ilN > 1 && Number.isFinite(parentLineHeight) && parentLineHeight > 0) {
|
|
421
|
-
const expectedHeight = ilN * parentLineHeight;
|
|
422
|
-
if (expectedHeight > rasterHeight) {
|
|
423
|
-
// Extend downward only — Chrome aligns the cap-top at the
|
|
424
|
-
// first line's cap-height position; extra space the
|
|
425
|
-
// expansion captures past the actual ink is empty (will
|
|
426
|
-
// raster as transparent, with `omitBackground: true`) and
|
|
427
|
-
// doesn't paint anything visible.
|
|
428
|
-
rasterHeight = expectedHeight;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
// DM-931: decorative ::first-letter drop caps frequently
|
|
432
|
-
// declare PADDING + BACKGROUND-IMAGE on the pseudo (e.g.
|
|
433
|
-
// `linear-gradient` behind the cap). The base char rect
|
|
434
|
-
// measures the GLYPH only — the padding-extended background
|
|
435
|
-
// box extends beyond on every side. Without expansion the
|
|
436
|
-
// rasterized PNG captures just the glyph and the gradient
|
|
437
|
-
// box renders truncated. Expand by the ::first-letter
|
|
438
|
-
// padding (top / right / bottom / left). Same omitBackground
|
|
439
|
-
// semantics: extra captured area outside the painted box is
|
|
440
|
-
// transparent and inert.
|
|
417
|
+
const flFloat = flStyle.float || flStyle.cssFloat || '';
|
|
441
418
|
const padT = parseFloat(flStyle.paddingTop) || 0;
|
|
442
419
|
const padR = parseFloat(flStyle.paddingRight) || 0;
|
|
443
420
|
const padB = parseFloat(flStyle.paddingBottom) || 0;
|
|
444
421
|
const padL = parseFloat(flStyle.paddingLeft) || 0;
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
422
|
+
if (flFloat === 'left' || flFloat === 'right') {
|
|
423
|
+
// DM-931: floated ::first-letter (drop cap) is positioned
|
|
424
|
+
// relative to the PARAGRAPH's content area, not the first
|
|
425
|
+
// character's line-box position. `Range.getBoundingClientRect`
|
|
426
|
+
// on the first character returns the GLYPH bounds at its
|
|
427
|
+
// line-1 position — which doesn't match where Chrome paints
|
|
428
|
+
// the float when `initial-letter` is set (the cap-top aligns
|
|
429
|
+
// to line-1's cap-top, shifting the painted box DOWN from
|
|
430
|
+
// the Range top by roughly the cap-height-vs-ascender delta).
|
|
431
|
+
// Compute the raster rect from the pseudo's computed
|
|
432
|
+
// padding-box (width/height + padding) + the paragraph's
|
|
433
|
+
// border-box origin + paragraph padding/border + pseudo
|
|
434
|
+
// margins.
|
|
435
|
+
const pBox = el.getBoundingClientRect();
|
|
436
|
+
const pPadT = parseFloat(cs.paddingTop) || 0;
|
|
437
|
+
const pPadL = parseFloat(cs.paddingLeft) || 0;
|
|
438
|
+
const pPadR = parseFloat(cs.paddingRight) || 0;
|
|
439
|
+
const pBorT = parseFloat(cs.borderTopWidth) || 0;
|
|
440
|
+
const pBorL = parseFloat(cs.borderLeftWidth) || 0;
|
|
441
|
+
const pBorR = parseFloat(cs.borderRightWidth) || 0;
|
|
442
|
+
const flMarT = parseFloat(flStyle.marginTop) || 0;
|
|
443
|
+
const flMarL = parseFloat(flStyle.marginLeft) || 0;
|
|
444
|
+
const flMarR = parseFloat(flStyle.marginRight) || 0;
|
|
445
|
+
const w = parseFloat(flStyle.width);
|
|
446
|
+
const h = parseFloat(flStyle.height);
|
|
447
|
+
const padW = (Number.isFinite(w) && w > 0 ? w : rasterWidth) + padL + padR;
|
|
448
|
+
const padH = (Number.isFinite(h) && h > 0 ? h : rasterHeight) + padT + padB;
|
|
449
|
+
rasterTop = pBox.y + pBorT + pPadT + flMarT - vp.y;
|
|
450
|
+
if (flFloat === 'left') {
|
|
451
|
+
rasterLeft = pBox.x + pBorL + pPadL + flMarL - vp.x;
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
rasterLeft = pBox.x + pBox.width - pBorR - pPadR - flMarR - padW - vp.x;
|
|
455
|
+
}
|
|
456
|
+
rasterWidth = padW;
|
|
457
|
+
rasterHeight = padH;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
// Non-floated ::first-letter (raised cap via font-size only,
|
|
461
|
+
// or `display: inline`). The Range rect tracks the painted
|
|
462
|
+
// glyph correctly; just expand the rect by the pseudo's
|
|
463
|
+
// padding so a `background-color` / gradient behind the
|
|
464
|
+
// glyph isn't truncated. Apply the older `initial-letter`
|
|
465
|
+
// height fallback for safety against under-tall Range
|
|
466
|
+
// measurements on float-less drop caps.
|
|
467
|
+
const ilRaw = flStyle.initialLetter || flStyle.webkitInitialLetter || '';
|
|
468
|
+
const ilN = parseFloat(ilRaw);
|
|
469
|
+
const parentLineHeight = parseFloat(cs.lineHeight);
|
|
470
|
+
if (Number.isFinite(ilN) && ilN > 1 && Number.isFinite(parentLineHeight) && parentLineHeight > 0) {
|
|
471
|
+
const expectedHeight = ilN * parentLineHeight;
|
|
472
|
+
if (expectedHeight > rasterHeight)
|
|
473
|
+
rasterHeight = expectedHeight;
|
|
474
|
+
}
|
|
475
|
+
if (padT > 0 || padR > 0 || padB > 0 || padL > 0) {
|
|
476
|
+
rasterTop -= padT;
|
|
477
|
+
rasterLeft -= padL;
|
|
478
|
+
rasterWidth += padL + padR;
|
|
479
|
+
rasterHeight += padT + padB;
|
|
480
|
+
}
|
|
450
481
|
}
|
|
451
482
|
}
|
|
452
483
|
rasterGlyphs.push({
|