pa_font 0.2.8 → 0.3.1
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/USAGE.md +45 -10
- package/dist/paFont.cjs +143 -15
- package/dist/paFont.cjs.map +1 -1
- package/dist/paFont.js +143 -15
- package/dist/paFont.js.map +1 -1
- package/paFont.d.ts +5 -0
- package/package.json +1 -1
package/dist/paFont.js
CHANGED
|
@@ -3295,6 +3295,7 @@ function layoutWithLines(prepared, maxWidth, lineHeight) {
|
|
|
3295
3295
|
//#endregion
|
|
3296
3296
|
//#region src/paFont/paragraphLayout.js
|
|
3297
3297
|
var DEFAULT_LINE_HEIGHT_RATIO = 1.2;
|
|
3298
|
+
var DEFAULT_PARAGRAPH_GAP = .5;
|
|
3298
3299
|
var HUGE_LAYOUT_WIDTH = 1e9;
|
|
3299
3300
|
var JUSTIFY_EPSILON = 1e-6;
|
|
3300
3301
|
var QUOTE_RE = /"/g;
|
|
@@ -3308,13 +3309,14 @@ function layoutParagraph(fontInstance, text, options = {}, state = {}) {
|
|
|
3308
3309
|
const textValue = String(text ?? "");
|
|
3309
3310
|
const layoutBox = resolveLayoutBox(normalized, state);
|
|
3310
3311
|
const retainedPreparedState = resolveRetainedPreparedState(state, normalized);
|
|
3311
|
-
const
|
|
3312
|
-
const
|
|
3312
|
+
const paragraphs = splitParagraphText(textValue, normalized.whiteSpace);
|
|
3313
|
+
const pretextState = shouldAttemptPretextLayout(normalized) ? layoutParagraphsWithPretext(paragraphs, normalized, retainedPreparedState, layoutBox) : null;
|
|
3314
|
+
const layoutState = pretextState != null && canUsePretextLayout(pretextState, normalized) ? pretextState : layoutParagraphsWithNative(fontInstance, paragraphs, normalized, layoutBox);
|
|
3313
3315
|
const measureWidth = createLazyTextMeasurer(fontInstance, normalized);
|
|
3314
3316
|
const lines = positionLines(fontInstance, applyOverflowClamping(layoutState.lines, normalized, layoutBox, measureWidth), normalized, layoutBox, measureWidth);
|
|
3315
3317
|
const textBBox = combineRects(lines.map((line) => line.bbox)) ?? emptyRect();
|
|
3316
3318
|
const textWidth = lines.reduce((max, line) => Math.max(max, line.width), 0);
|
|
3317
|
-
const textHeight = lines
|
|
3319
|
+
const textHeight = resolvePositionedTextHeight(lines, layoutBox.contentY);
|
|
3318
3320
|
const finalLayoutBox = finalizeLayoutBox(layoutBox, normalized, textHeight);
|
|
3319
3321
|
const cachedPrepared = pretextState?.prepared ?? retainedPreparedState.prepared ?? null;
|
|
3320
3322
|
const cachedPreparedWhiteSpace = pretextState?.preparedWhiteSpace ?? retainedPreparedState.preparedWhiteSpace ?? null;
|
|
@@ -3326,6 +3328,8 @@ function layoutParagraph(fontInstance, text, options = {}, state = {}) {
|
|
|
3326
3328
|
y: finalLayoutBox.contentBox.y,
|
|
3327
3329
|
width: textWidth,
|
|
3328
3330
|
height: textHeight,
|
|
3331
|
+
viewportHeight: finalLayoutBox.contentBox.h,
|
|
3332
|
+
maxScrollTop: Math.max(0, textHeight - finalLayoutBox.contentBox.h),
|
|
3329
3333
|
lineCount: lines.length,
|
|
3330
3334
|
bbox: textBBox,
|
|
3331
3335
|
contentBox: { ...finalLayoutBox.contentBox },
|
|
@@ -3351,8 +3355,13 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3351
3355
|
], null));
|
|
3352
3356
|
const width = normalizeDimension(options.width);
|
|
3353
3357
|
const height = normalizeDimension(options.height);
|
|
3358
|
+
const gap = normalizeGap(options.gap);
|
|
3359
|
+
const overflow = normalizeEnum(options.overflow, ["visible", "hidden"], "visible");
|
|
3360
|
+
const overflowY = resolveOverflowY(options.overflowY, overflow);
|
|
3354
3361
|
if (options.width != null && width == null) throw new TypeError("font.paragraph() option \"width\" must be a positive number.");
|
|
3355
3362
|
if (options.height != null && height == null) throw new TypeError("font.paragraph() option \"height\" must be a positive number.");
|
|
3363
|
+
if (options.gap != null && gap == null) throw new TypeError("font.paragraph() option \"gap\" must be a non-negative number.");
|
|
3364
|
+
if (overflowY === "scroll" && height == null) throw new TypeError("font.paragraph() option \"height\" is required when \"overflowY\" is \"scroll\".");
|
|
3356
3365
|
const font = resolveCanvasFont(fontInstance, textOptions.size, options);
|
|
3357
3366
|
return {
|
|
3358
3367
|
...textOptions,
|
|
@@ -3367,6 +3376,7 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3367
3376
|
], wrapDefaults.overflowWrap)),
|
|
3368
3377
|
width,
|
|
3369
3378
|
height,
|
|
3379
|
+
gap: gap ?? DEFAULT_PARAGRAPH_GAP,
|
|
3370
3380
|
lineHeight: resolveLineHeight(options.lineHeight, textOptions.size),
|
|
3371
3381
|
align: normalizeEnum(options.align, [
|
|
3372
3382
|
"left",
|
|
@@ -3389,7 +3399,8 @@ function normalizeParagraphOptions(fontInstance, options = {}) {
|
|
|
3389
3399
|
"break-all",
|
|
3390
3400
|
"keep-all"
|
|
3391
3401
|
], wrapDefaults.wordBreak),
|
|
3392
|
-
overflow
|
|
3402
|
+
overflow,
|
|
3403
|
+
overflowY,
|
|
3393
3404
|
textOverflow: normalizeNullableEnum(options.textOverflow, ["clip", "ellipsis"], null),
|
|
3394
3405
|
maxLines: normalizeMaxLines(options.maxLines),
|
|
3395
3406
|
ellipsis: normalizeEllipsis(options.ellipsis),
|
|
@@ -3417,6 +3428,44 @@ function resolveCanvasFont(fontInstance, size, options = {}) {
|
|
|
3417
3428
|
function canReusePreparedParagraphState(previousState, previousOptions, nextOptions) {
|
|
3418
3429
|
return previousState?.prepared != null && previousState.preparedWhiteSpace === resolvePretextWhiteSpace(nextOptions.whiteSpace) && previousOptions?.font === nextOptions.font;
|
|
3419
3430
|
}
|
|
3431
|
+
function layoutParagraphsWithPretext(paragraphs, options, state, layoutBox) {
|
|
3432
|
+
const retainedPrepared = Array.isArray(state.prepared) ? state.prepared : state.prepared != null ? [state.prepared] : [];
|
|
3433
|
+
const paragraphStates = paragraphs.map((paragraph, paragraphIndex) => layoutWithPretext(paragraph, options, {
|
|
3434
|
+
prepared: retainedPrepared[paragraphIndex] ?? null,
|
|
3435
|
+
preparedWhiteSpace: state.preparedWhiteSpace,
|
|
3436
|
+
font: options.font
|
|
3437
|
+
}, layoutBox));
|
|
3438
|
+
return {
|
|
3439
|
+
lines: annotateParagraphLines(paragraphStates),
|
|
3440
|
+
prepared: paragraphStates.map((paragraphState) => paragraphState.prepared ?? null),
|
|
3441
|
+
preparedWhiteSpace: paragraphStates[0]?.preparedWhiteSpace ?? resolvePretextWhiteSpace(options.whiteSpace),
|
|
3442
|
+
layoutEngine: "pretext",
|
|
3443
|
+
usedOverflowWrapFallbackBreaks: paragraphStates.some((paragraphState) => paragraphState.usedOverflowWrapFallbackBreaks)
|
|
3444
|
+
};
|
|
3445
|
+
}
|
|
3446
|
+
function layoutParagraphsWithNative(fontInstance, paragraphs, options, layoutBox) {
|
|
3447
|
+
return {
|
|
3448
|
+
lines: annotateParagraphLines(paragraphs.map((paragraph) => layoutWithNative(fontInstance, paragraph, options, layoutBox))),
|
|
3449
|
+
prepared: null,
|
|
3450
|
+
preparedWhiteSpace: null,
|
|
3451
|
+
layoutEngine: "native"
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
function annotateParagraphLines(paragraphStates) {
|
|
3455
|
+
const lines = [];
|
|
3456
|
+
paragraphStates.forEach((paragraphState, paragraphIndex) => {
|
|
3457
|
+
paragraphState.lines.forEach((line, lineIndex) => {
|
|
3458
|
+
lines.push({
|
|
3459
|
+
...line,
|
|
3460
|
+
start: null,
|
|
3461
|
+
end: null,
|
|
3462
|
+
paragraphIndex,
|
|
3463
|
+
paragraphEnd: lineIndex === paragraphState.lines.length - 1
|
|
3464
|
+
});
|
|
3465
|
+
});
|
|
3466
|
+
});
|
|
3467
|
+
return lines;
|
|
3468
|
+
}
|
|
3420
3469
|
function layoutWithPretext(text, options, state, layoutBox) {
|
|
3421
3470
|
const preparedWhiteSpace = resolvePretextWhiteSpace(options.whiteSpace);
|
|
3422
3471
|
const prepared = state.prepared != null && state.preparedWhiteSpace === preparedWhiteSpace && state.font === options.font ? state.prepared : prepareWithSegments(text, options.font, { whiteSpace: preparedWhiteSpace });
|
|
@@ -3540,8 +3589,8 @@ function applyOverflowClamping(lines, options, layoutBox, measureWidth) {
|
|
|
3540
3589
|
const contentWidth = layoutBox.contentWidth;
|
|
3541
3590
|
const result = lines.map((line) => ({ ...line }));
|
|
3542
3591
|
let lineLimit = options.maxLines;
|
|
3543
|
-
if (options
|
|
3544
|
-
const visibleLineCount =
|
|
3592
|
+
if (shouldClampLinesToHeight(options) && layoutBox.clipContentHeight != null) {
|
|
3593
|
+
const visibleLineCount = countVisibleLinesForHeight(result, options, layoutBox.clipContentHeight);
|
|
3545
3594
|
lineLimit = lineLimit == null ? visibleLineCount : Math.min(lineLimit, visibleLineCount);
|
|
3546
3595
|
}
|
|
3547
3596
|
let clippedByCount = false;
|
|
@@ -3553,14 +3602,30 @@ function applyOverflowClamping(lines, options, layoutBox, measureWidth) {
|
|
|
3553
3602
|
}
|
|
3554
3603
|
}
|
|
3555
3604
|
if (result.length === 0) return result;
|
|
3556
|
-
if (options.overflow === "hidden" && options.whiteSpace === "nowrap"
|
|
3557
|
-
|
|
3605
|
+
if (options.overflow === "hidden" && options.whiteSpace === "nowrap") {
|
|
3606
|
+
for (let index = 0; index < result.length; index += 1) if (result[index].width > contentWidth + JUSTIFY_EPSILON) result[index] = truncateLineToWidth(result[index], contentWidth, measureWidth, options.textOverflow === "ellipsis" ? options.ellipsis : false);
|
|
3607
|
+
}
|
|
3608
|
+
if (clippedByCount && shouldEllipsizeClampedLines(options)) {
|
|
3558
3609
|
const lastIndex = result.length - 1;
|
|
3559
3610
|
result[lastIndex] = truncateLineToWidth(result[lastIndex], contentWidth, measureWidth, options.ellipsis);
|
|
3560
3611
|
result[lastIndex].hardBreak = false;
|
|
3612
|
+
result[lastIndex].paragraphEnd = true;
|
|
3561
3613
|
}
|
|
3562
3614
|
return result;
|
|
3563
3615
|
}
|
|
3616
|
+
function countVisibleLinesForHeight(lines, options, maxHeight) {
|
|
3617
|
+
let visibleLineCount = 0;
|
|
3618
|
+
let consumedHeight = 0;
|
|
3619
|
+
const lineBoxHeight = options.lineHeight;
|
|
3620
|
+
const paragraphGap = lineBoxHeight * options.gap;
|
|
3621
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
3622
|
+
if (consumedHeight + lineBoxHeight > maxHeight + JUSTIFY_EPSILON) break;
|
|
3623
|
+
consumedHeight += lineBoxHeight;
|
|
3624
|
+
visibleLineCount += 1;
|
|
3625
|
+
if (lines[index].paragraphEnd && index < lines.length - 1) consumedHeight += paragraphGap;
|
|
3626
|
+
}
|
|
3627
|
+
return visibleLineCount;
|
|
3628
|
+
}
|
|
3564
3629
|
function truncateLineToWidth(line, maxWidth, measureWidth, suffix) {
|
|
3565
3630
|
const suffixText = suffix === false ? "" : suffix;
|
|
3566
3631
|
if ((suffixText.length > 0 ? measureWidth(suffixText) : 0) > maxWidth + JUSTIFY_EPSILON) return {
|
|
@@ -3585,13 +3650,17 @@ function shouldEllipsizeClampedLines(options) {
|
|
|
3585
3650
|
function positionLines(fontInstance, lines, options, layoutBox, measureWidth) {
|
|
3586
3651
|
const ascent = getFontAscender(fontInstance, options.size);
|
|
3587
3652
|
const lineBoxHeight = options.lineHeight;
|
|
3653
|
+
const paragraphGap = lineBoxHeight * options.gap;
|
|
3588
3654
|
let cursor = 0;
|
|
3655
|
+
let cursorY = layoutBox.contentY;
|
|
3589
3656
|
return lines.map((line, index) => {
|
|
3590
3657
|
const justified = shouldJustifyLine(line, index, lines.length, options);
|
|
3591
3658
|
const offsetX = justified ? 0 : resolveAlignOffset(options.align, line.width, layoutBox.contentWidth);
|
|
3592
3659
|
const x = layoutBox.contentX + offsetX;
|
|
3593
|
-
const y =
|
|
3660
|
+
const y = cursorY;
|
|
3594
3661
|
const baseline = y + ascent;
|
|
3662
|
+
const start = line.start ?? cursor;
|
|
3663
|
+
const end = line.end ?? start + line.text.length;
|
|
3595
3664
|
const fragments = justified ? buildJustifiedFragments(line, layoutBox.contentX, layoutBox.contentWidth, measureWidth) : [{
|
|
3596
3665
|
text: line.text,
|
|
3597
3666
|
x,
|
|
@@ -3608,8 +3677,8 @@ function positionLines(fontInstance, lines, options, layoutBox, measureWidth) {
|
|
|
3608
3677
|
const positioned = {
|
|
3609
3678
|
index,
|
|
3610
3679
|
text: line.text,
|
|
3611
|
-
start
|
|
3612
|
-
end
|
|
3680
|
+
start,
|
|
3681
|
+
end,
|
|
3613
3682
|
x,
|
|
3614
3683
|
y,
|
|
3615
3684
|
width,
|
|
@@ -3619,10 +3688,21 @@ function positionLines(fontInstance, lines, options, layoutBox, measureWidth) {
|
|
|
3619
3688
|
hardBreak: line.hardBreak,
|
|
3620
3689
|
fragments
|
|
3621
3690
|
};
|
|
3622
|
-
cursor =
|
|
3691
|
+
cursor = end;
|
|
3692
|
+
if (line.hardBreak) cursor += 1;
|
|
3693
|
+
if (line.paragraphEnd && index < lines.length - 1) {
|
|
3694
|
+
cursor += 2;
|
|
3695
|
+
cursorY += paragraphGap;
|
|
3696
|
+
}
|
|
3697
|
+
cursorY += lineBoxHeight;
|
|
3623
3698
|
return positioned;
|
|
3624
3699
|
});
|
|
3625
3700
|
}
|
|
3701
|
+
function resolvePositionedTextHeight(lines, contentY) {
|
|
3702
|
+
if (lines.length === 0) return 0;
|
|
3703
|
+
const lastLine = lines[lines.length - 1];
|
|
3704
|
+
return lastLine.y + lastLine.height - contentY;
|
|
3705
|
+
}
|
|
3626
3706
|
function buildJustifiedFragments(line, contentX, contentWidth, measureWidth) {
|
|
3627
3707
|
const tokens = splitPreservingWhitespace(line.text);
|
|
3628
3708
|
const expandable = tokens.reduce((count, token, index) => {
|
|
@@ -3653,7 +3733,7 @@ function buildJustifiedFragments(line, contentX, contentWidth, measureWidth) {
|
|
|
3653
3733
|
return fragments;
|
|
3654
3734
|
}
|
|
3655
3735
|
function shouldJustifyLine(line, index, lineCount, options) {
|
|
3656
|
-
return options.align === "justify" && index < lineCount - 1 && !line.hardBreak && /\S\s+\S/u.test(line.text);
|
|
3736
|
+
return options.align === "justify" && index < lineCount - 1 && !line.hardBreak && !line.paragraphEnd && /\S\s+\S/u.test(line.text);
|
|
3657
3737
|
}
|
|
3658
3738
|
function resolveAlignOffset(align, lineWidth, maxWidth) {
|
|
3659
3739
|
if (align === "center") return (maxWidth - lineWidth) * .5;
|
|
@@ -3734,7 +3814,7 @@ function finalizeLayoutBox(layoutBox, options, textHeight) {
|
|
|
3734
3814
|
x: layoutBox.contentX,
|
|
3735
3815
|
y: layoutBox.contentY,
|
|
3736
3816
|
w: layoutBox.contentWidth,
|
|
3737
|
-
h: options
|
|
3817
|
+
h: shouldClipToContentHeight(options) ? contentHeight : textHeight
|
|
3738
3818
|
}
|
|
3739
3819
|
};
|
|
3740
3820
|
}
|
|
@@ -3750,6 +3830,19 @@ function normalizeNullableEnum(value, supported, fallback) {
|
|
|
3750
3830
|
if (value == null) return fallback;
|
|
3751
3831
|
return typeof value === "string" && supported.includes(value) ? value : fallback;
|
|
3752
3832
|
}
|
|
3833
|
+
function resolveOverflowY(value, overflow) {
|
|
3834
|
+
return normalizeEnum(value, [
|
|
3835
|
+
"visible",
|
|
3836
|
+
"hidden",
|
|
3837
|
+
"scroll"
|
|
3838
|
+
], overflow === "hidden" ? "hidden" : "visible");
|
|
3839
|
+
}
|
|
3840
|
+
function shouldClampLinesToHeight(options) {
|
|
3841
|
+
return options.overflowY === "hidden";
|
|
3842
|
+
}
|
|
3843
|
+
function shouldClipToContentHeight(options) {
|
|
3844
|
+
return options.overflow === "hidden" || options.overflowY === "hidden" || options.overflowY === "scroll";
|
|
3845
|
+
}
|
|
3753
3846
|
function normalizeEllipsis(value) {
|
|
3754
3847
|
if (value === false) return false;
|
|
3755
3848
|
if (typeof value === "string") return value;
|
|
@@ -3763,6 +3856,9 @@ function normalizeMaxLines(value) {
|
|
|
3763
3856
|
function normalizeDimension(value) {
|
|
3764
3857
|
return Number.isFinite(value) && value > 0 ? value : null;
|
|
3765
3858
|
}
|
|
3859
|
+
function normalizeGap(value) {
|
|
3860
|
+
return Number.isFinite(value) && value >= 0 ? Number(value) : null;
|
|
3861
|
+
}
|
|
3766
3862
|
function normalizeSpacing(value) {
|
|
3767
3863
|
if (value == null) return zeroSpacing();
|
|
3768
3864
|
if (Number.isFinite(value)) {
|
|
@@ -3877,6 +3973,27 @@ function resolveRetainedPreparedState(state, options) {
|
|
|
3877
3973
|
function isHardBreak(prepared, line) {
|
|
3878
3974
|
return prepared.kinds?.[line.end.segmentIndex] === "hard-break";
|
|
3879
3975
|
}
|
|
3976
|
+
function splitParagraphText(text, whiteSpace) {
|
|
3977
|
+
const normalized = String(text ?? "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
3978
|
+
const paragraphs = [];
|
|
3979
|
+
const lines = normalized.split("\n");
|
|
3980
|
+
let currentLines = [];
|
|
3981
|
+
const pushCurrentParagraph = () => {
|
|
3982
|
+
if (currentLines.length === 0) return;
|
|
3983
|
+
const paragraph = whiteSpace === "pre-wrap" ? currentLines.join("\n") : currentLines.join("\n").replace(/\s+/gu, " ").trim();
|
|
3984
|
+
currentLines = [];
|
|
3985
|
+
if (paragraph.length > 0) paragraphs.push(paragraph);
|
|
3986
|
+
};
|
|
3987
|
+
lines.forEach((line) => {
|
|
3988
|
+
if (/^[\t ]*$/u.test(line)) {
|
|
3989
|
+
pushCurrentParagraph();
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
currentLines.push(line);
|
|
3993
|
+
});
|
|
3994
|
+
pushCurrentParagraph();
|
|
3995
|
+
return paragraphs;
|
|
3996
|
+
}
|
|
3880
3997
|
function normalizeNativeText(text, whiteSpace) {
|
|
3881
3998
|
if (whiteSpace === "pre-wrap") return String(text ?? "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
3882
3999
|
return String(text ?? "").replace(/\s+/gu, " ").trim();
|
|
@@ -4162,6 +4279,7 @@ var paParagraph = class paParagraph {
|
|
|
4162
4279
|
if (!ctx || typeof ctx.fillText !== "function") throw new TypeError("drawText() expects a CanvasRenderingContext2D.");
|
|
4163
4280
|
const fill = options.fill !== false;
|
|
4164
4281
|
const stroke = options.stroke === true;
|
|
4282
|
+
const scrollTop = clampScrollTop(options.scrollTop, this.metrics.maxScrollTop);
|
|
4165
4283
|
if (!fill && !stroke) return;
|
|
4166
4284
|
this._syncLayoutWithContext(ctx);
|
|
4167
4285
|
ctx.save();
|
|
@@ -4170,12 +4288,13 @@ var paParagraph = class paParagraph {
|
|
|
4170
4288
|
ctx.textBaseline = "alphabetic";
|
|
4171
4289
|
if (options.fillStyle != null) ctx.fillStyle = options.fillStyle;
|
|
4172
4290
|
if (options.strokeStyle != null) ctx.strokeStyle = options.strokeStyle;
|
|
4173
|
-
if (this.options
|
|
4291
|
+
if (shouldClipParagraph(this.options) && this._state.layoutBox?.clipBox) {
|
|
4174
4292
|
const clipBox = this._state.layoutBox.clipBox;
|
|
4175
4293
|
ctx.beginPath();
|
|
4176
4294
|
ctx.rect(clipBox.x, clipBox.y, clipBox.w, clipBox.h);
|
|
4177
4295
|
ctx.clip();
|
|
4178
4296
|
}
|
|
4297
|
+
if (scrollTop > 0) ctx.translate(0, -scrollTop);
|
|
4179
4298
|
this._state.lines.forEach((line) => {
|
|
4180
4299
|
line.fragments.forEach((fragment) => {
|
|
4181
4300
|
if (fill) ctx.fillText(fragment.text, fragment.x, line.baseline);
|
|
@@ -4226,6 +4345,8 @@ var paParagraph = class paParagraph {
|
|
|
4226
4345
|
this.metrics = {
|
|
4227
4346
|
...state.metrics,
|
|
4228
4347
|
bbox: { ...state.metrics.bbox },
|
|
4348
|
+
viewportHeight: state.metrics.viewportHeight,
|
|
4349
|
+
maxScrollTop: state.metrics.maxScrollTop,
|
|
4229
4350
|
contentBox: state.metrics.contentBox ? { ...state.metrics.contentBox } : void 0,
|
|
4230
4351
|
paddingBox: state.metrics.paddingBox ? { ...state.metrics.paddingBox } : void 0,
|
|
4231
4352
|
marginBox: state.metrics.marginBox ? { ...state.metrics.marginBox } : void 0,
|
|
@@ -4320,6 +4441,13 @@ function normalizeParagraphPointOptions(options = {}) {
|
|
|
4320
4441
|
layout: options.layout ?? "current"
|
|
4321
4442
|
};
|
|
4322
4443
|
}
|
|
4444
|
+
function shouldClipParagraph(options) {
|
|
4445
|
+
return options.overflow === "hidden" || options.overflowY === "hidden" || options.overflowY === "scroll";
|
|
4446
|
+
}
|
|
4447
|
+
function clampScrollTop(value, maxScrollTop) {
|
|
4448
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
4449
|
+
return Math.min(Number(value), maxScrollTop ?? 0);
|
|
4450
|
+
}
|
|
4323
4451
|
//#endregion
|
|
4324
4452
|
//#region src/paFont/paFont.js
|
|
4325
4453
|
var browserFontRegistrationId = 0;
|