Skip to content
Topaz6.0 · Before release
Download

Search documentation

Specification 6.0 · Not released · Tested product 5.21.3

Use arrow keys to choose a result. Press Enter to open.

Type an API name, diagnostic number, rule, or project topic.

    Library

    std.typeset.lineBadness

    Computes the existing fixed-point line-badness cost from typed physical distances.

    lineBadness(width: Length<Pt>, target: Length<Pt>, charCount: int, spaces: int, kind: BreakKind, isLast: bool, justificationB: int, hyphenAdvance: Length<Pt>) -> Result<int, TypesetError>
    Receiver
    Not applicable
    Minimum arity
    8
    Maximum arity
    8

    Declaration and parameters

    Link

    Availability

    Included by default: Pending

    Import std.typeset in language mode 5.21.

    The current compiler selects std/typeset.tpz for this language mode. Availability in other released editions and inclusion in each installed distribution are Pending.

    Source evidence

    Receiver

    Parameter constraints

    Public measurement fields use Length<Pt>. Widths, advances, tracking, stretch, shrink, physical targets, insets, font sizes, and optional width limits keep that type across input and output records. Explicit Length conversion functions remain the integer interchange boundary.

    Box.width, Box.trackingAfter, Glue.width, Glue.trackingAfter, Glue.stretch, Glue.shrink, and Penalty.width have type Length<Pt>.

    BreakCluster.advance, BreakCluster.trackingAfter, BreakPolicy.narrowestWordTarget, and BreakPolicy.bodyWordTarget have type Length<Pt>.

    LatinSpacing.fontSizePt, JustificationPolicy.maxAdjustment, and JustificationPolicy.maxGapAdjustment have type Length<Pt>.

    LineGeometry.bodyTarget, LineGeometry.firstTarget, and LineGeometry.dropCapInset have type Length<Pt>.

    PlanLine.target, PlanLine.rawTextWidth, PlanLine.trimmedTextWidth, PlanLine.costTextWidth, and PlanLine.selectedPenaltyWidth have type Length<Pt>. PlanLine.postValidationWidthLimit has type Option<Length<Pt>>.

    An int, a float, or a Length with another unit marker is not an implicit point-length argument. Convert physical units explicitly with toPt() before constructing a typesetting record.

    Indices, counts, penalties, costs, and dimensionless ratios retain their declared types. LatinSpacing.maxLetterSpacingEm is a relative Length<Em>. Resolve it to Length<Pt> with fontSizePt before selecting the computation grid.

    Paragraph.grid selects quantization at the computation boundary. ScaledPoint uses the exact scaled-point integer. MilliPoint uses the existing nearest-even conversion to millipoints. The selected grid never changes the physical interpretation of a public Length<Pt> value.

    Returned distances are converted from the computation grid into Length<Pt> at the output boundary. ParagraphPlan.grid reports the computation policy and is not needed to interpret its distances.

    The public type change preserves the selected cost model. FixedPoint retains its MilliPoint computation requirement. Word-space and CJK ratio calculations keep their independent floor rules. The relative letter-spacing distance is resolved and quantized through the shared Length conversions before it contributes to capacity.

    The public line-badness entry point also receives width, target, and hyphen advance as Length<Pt>. It converts those distances to millipoints at entry and preserves its existing integer cost calculation.

    lineBadness(width: Length<Pt>, target: Length<Pt>, charCount: int, spaces: int, kind: BreakKind, isLast: bool, justificationB: int, hyphenAdvance: Length<Pt>) -> Result<int, TypesetError> is the public entry point. lineBadnessMpt is absent and importing it is rejected with TPZ3009.

    The three distances require Length<Pt>. A raw scalar or another unit marker is rejected with TPZ5001. Width and hyphen advance may be negative. justificationB accepts every int and can make the resulting cost negative.

    Evaluate all eight argument expressions once in source order before entering the function. Convert width, target, and hyphenAdvance to millipoints in that order with the shared nearest-even rule.

    The converted target must be positive. charCount and spaces must each be nonnegative and need not satisfy a relation to each other. Invalid inputs return Err containing TypesetError.InvalidInput before cost arithmetic. The explanatory message text is not fixed.

    Let w, t, and h be the converted distances, c the character count, s the space count, and j the supplied justification cost. Let B be 1,000,000 and R be 100,000,000.

    For a nonnegative n and positive d, H gives n divided by d rounded to the nearest integer with ties upward. H describes cost rounding. Physical Length conversion keeps its separate nearest-even rule.

    The following sequence uses checked int operations in the stated order. A failing intermediate operation stops with runtime diagnostic TPZ4004. It does not return TypesetError or replace overflow with a bounded cost.

    Set effective to w + h for LatinSoftHyphen and to w for every other kind. Set slack to t - effective and absolute to the absolute value of slack.

    Set raw to 4 R when absolute is at least 4 t. Otherwise set raw to absolute * R / t with integer division. This explicit ratio cap does not change a supplied length.

    Set capacity to 100 + s * 45 when slack is nonnegative and to 100 + s * 25 otherwise. Set ratio = H(raw * 100, capacity), then q = H(ratio * ratio, R), then cost = H(q * (1000 * B), R).

    If isLast is true, replace cost with H(cost * 2, 5). Add 500 B when isLast is true and `w 100 < t * 52`. The strict comparison uses the original converted width and also applies when charCount is zero.

    If slack is negative, add 20000 * B + H(20000 * B * ratio, R). Add 65 B for LatinHyphen or LatinSoftHyphen. Add 50000 B for HardFallback. The other break kinds add no break penalty.

    If c is at most two, add 275 B. Then add 10 B and j in that order and return the result in Ok. The hyphenAdvance input affects width for LatinSoftHyphen and is ignored for the other kinds.

    An exact fit with more than two characters, no special break penalty, and zero justification cost returns 10000000. The documented 90 point line against a 100 point target with nine characters and two spaces returns 12770080.

    The function performs no I/O, changes no input, and reads no font, paragraph, or global grid state. Effects from argument evaluation remain visible on InvalidInput or a later arithmetic fault.

    An arithmetic fault identifies the public lineBadness call as its primary source location. Argument effects already performed remain visible and later expressions do not run.

    Result

    The declared result type is Result<int, TypesetError>.

    Effects

    Failures

    Result and effects

    Link

    Convert the three point distances to nearest-even millipoints and compute the specified checked fixed-point cost. A nonpositive converted target or negative count returns TypesetError.InvalidInput. Arithmetic overflow raises TPZ4004.

    Why

    Link

    A function name describes the computation while Length<Pt> carries its physical unit. One typed entry point avoids a second millipoint API for the same line-badness calculation.

    Related entries

    Link

    std.typeset

    Give public typesetting distances a point-length type

    Link
    Ruletopaz.stdlib.contract.typeset-length-pt.rule

    Give public typesetting distances a point-length type

    Public measurement fields use Length<Pt>. Widths, advances, tracking, stretch, shrink, physical targets, insets, font sizes, and optional width limits keep that type across input and output records. Explicit Length conversion functions remain the integer interchange boundary.

    Box.width, Box.trackingAfter, Glue.width, Glue.trackingAfter, Glue.stretch, Glue.shrink, and Penalty.width have type Length<Pt>.

    BreakCluster.advance, BreakCluster.trackingAfter, BreakPolicy.narrowestWordTarget, and BreakPolicy.bodyWordTarget have type Length<Pt>.

    LatinSpacing.fontSizePt, JustificationPolicy.maxAdjustment, and JustificationPolicy.maxGapAdjustment have type Length<Pt>.

    LineGeometry.bodyTarget, LineGeometry.firstTarget, and LineGeometry.dropCapInset have type Length<Pt>.

    PlanLine.target, PlanLine.rawTextWidth, PlanLine.trimmedTextWidth, PlanLine.costTextWidth, and PlanLine.selectedPenaltyWidth have type Length<Pt>. PlanLine.postValidationWidthLimit has type Option<Length<Pt>>.

    An int, a float, or a Length with another unit marker is not an implicit point-length argument. Convert physical units explicitly with toPt() before constructing a typesetting record.

    Indices, counts, penalties, costs, and dimensionless ratios retain their declared types. LatinSpacing.maxLetterSpacingEm is a relative Length<Em>. Resolve it to Length<Pt> with fontSizePt before selecting the computation grid.

    Paragraph.grid selects quantization at the computation boundary. ScaledPoint uses the exact scaled-point integer. MilliPoint uses the existing nearest-even conversion to millipoints. The selected grid never changes the physical interpretation of a public Length<Pt> value.

    Returned distances are converted from the computation grid into Length<Pt> at the output boundary. ParagraphPlan.grid reports the computation policy and is not needed to interpret its distances.

    The public type change preserves the selected cost model. FixedPoint retains its MilliPoint computation requirement. Word-space and CJK ratio calculations keep their independent floor rules. The relative letter-spacing distance is resolved and quantized through the shared Length conversions before it contributes to capacity.

    The public line-badness entry point also receives width, target, and hyphen advance as Length<Pt>. It converts those distances to millipoints at entry and preserves its existing integer cost calculation.

    Why

    A physical distance carries the same Length<Pt> type in application geometry and paragraph planning. The type prevents a grid selector or an unlabelled scalar from silently changing the distance.

    Source evidence

    Use point lengths in Box

    Link
    main.tpzUse point lengths in BoxOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Box = ts.Box {
    3. unitIndex: 0,
    4. text: "A",
    5. width: 12pt,
    6. trackingAfter: 0pt
    7. }
    8. let distance: Length<Pt> = value.width
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in Box

    Link
    main.tpzReject untyped physical distances in BoxOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Box = ts.Box {
    3. unitIndex: 0,
    4. text: "A",
    5. width: 12,
    6. trackingAfter: 0
    7. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:5:10
    Source evidence

    Use point lengths in Glue

    Link
    main.tpzUse point lengths in GlueOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Glue = ts.Glue {
    3. unitIndex: 1,
    4. text: " ",
    5. width: 3pt,
    6. trackingAfter: 0pt,
    7. stretch: 1pt,
    8. shrink: 1pt
    9. }
    10. let distance: Length<Pt> = value.width
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in Glue

    Link
    main.tpzReject untyped physical distances in GlueOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Glue = ts.Glue {
    3. unitIndex: 1,
    4. text: " ",
    5. width: 3,
    6. trackingAfter: 0,
    7. stretch: 1,
    8. shrink: 1
    9. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:5:10
    Source evidence

    Use point lengths in Penalty

    Link
    main.tpzUse point lengths in PenaltyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Penalty = ts.Penalty {
    3. unitEnd: 1,
    4. width: 0pt,
    5. rule: ts.BreakRule.Forced(),
    6. kind: ts.BreakKind.ForcedEnd(),
    7. flagged: false
    8. }
    9. let distance: Length<Pt> = value.width
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in Penalty

    Link
    main.tpzReject untyped physical distances in PenaltyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.Penalty = ts.Penalty {
    3. unitEnd: 1,
    4. width: 0,
    5. rule: ts.BreakRule.Forced(),
    6. kind: ts.BreakKind.ForcedEnd(),
    7. flagged: false
    8. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:4:10
    Source evidence

    Use point lengths in BreakPolicy

    Link
    main.tpzUse point lengths in BreakPolicyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.BreakPolicy = ts.BreakPolicy {
    3. mode: ts.BreakMode.Character(),
    4. rules: ts.KinsokuRules.Unicode16Ja(),
    5. forbidBefore: [],
    6. forbidAfter: [],
    7. boundaryAllowed: [true],
    8. generatedHyphenEnds: [],
    9. protectFittingLatin: true,
    10. preserveShortWords: true,
    11. narrowestWordTarget: 12pt,
    12. bodyWordTarget: 24pt
    13. }
    14. let distance: Length<Pt> = value.narrowestWordTarget
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in BreakPolicy

    Link
    main.tpzReject untyped physical distances in BreakPolicyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.BreakPolicy = ts.BreakPolicy {
    3. mode: ts.BreakMode.Character(),
    4. rules: ts.KinsokuRules.Unicode16Ja(),
    5. forbidBefore: [],
    6. forbidAfter: [],
    7. boundaryAllowed: [true],
    8. generatedHyphenEnds: [],
    9. protectFittingLatin: true,
    10. preserveShortWords: true,
    11. narrowestWordTarget: 12,
    12. bodyWordTarget: 24
    13. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:11:24
    Source evidence

    Use point lengths in BreakCluster

    Link
    main.tpzUse point lengths in BreakClusterOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.BreakCluster = ts.BreakCluster {
    3. text: "A",
    4. advance: 12pt,
    5. trackingAfter: 0pt
    6. }
    7. let distance: Length<Pt> = value.advance
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in BreakCluster

    Link
    main.tpzReject untyped physical distances in BreakClusterOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.BreakCluster = ts.BreakCluster {
    3. text: "A",
    4. advance: 12,
    5. trackingAfter: 0
    6. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:4:12
    Source evidence

    Use point lengths in LatinSpacing

    Link
    main.tpzUse point lengths in LatinSpacingOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.LatinSpacing = ts.LatinSpacing {
    3. minWordSpaceRatio: 0.8,
    4. maxWordSpaceRatio: 1.33,
    5. maxLetterSpacingEm: 0.01em,
    6. fontSizePt: 12pt
    7. }
    8. let distance: Length<Pt> = value.fontSizePt
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in LatinSpacing

    Link
    main.tpzReject untyped physical distances in LatinSpacingOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.LatinSpacing = ts.LatinSpacing {
    3. minWordSpaceRatio: 0.8,
    4. maxWordSpaceRatio: 1.33,
    5. maxLetterSpacingEm: 0.01em,
    6. fontSizePt: 12.0
    7. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:6:15
    Source evidence

    Use point lengths in JustificationPolicy

    Link
    main.tpzUse point lengths in JustificationPolicyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.JustificationPolicy = ts.JustificationPolicy {
    3. mode: ts.JustificationMode.Unjustified(),
    4. minGapCount: 0,
    5. minLineWidthRatioM: 0,
    6. minFinalLineWidthRatioM: None(),
    7. maxAdjustment: 12pt,
    8. maxGapAdjustment: 3pt,
    9. maxGapRatioR: 0,
    10. latinSpacing: None(),
    11. cjkStretchRatio: 0.0
    12. }
    13. let distance: Length<Pt> = value.maxAdjustment
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in JustificationPolicy

    Link
    main.tpzReject untyped physical distances in JustificationPolicyOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.JustificationPolicy = ts.JustificationPolicy {
    3. mode: ts.JustificationMode.Unjustified(),
    4. minGapCount: 0,
    5. minLineWidthRatioM: 0,
    6. minFinalLineWidthRatioM: None(),
    7. maxAdjustment: 12,
    8. maxGapAdjustment: 3,
    9. maxGapRatioR: 0,
    10. latinSpacing: None(),
    11. cjkStretchRatio: 0.0
    12. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:7:18
    Source evidence

    Use point lengths in LineGeometry

    Link
    main.tpzUse point lengths in LineGeometryOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.LineGeometry = ts.LineGeometry {
    3. bodyTarget: 24pt,
    4. firstTarget: 20pt,
    5. dropCapSpan: 0,
    6. dropCapInset: 0pt
    7. }
    8. let distance: Length<Pt> = value.bodyTarget
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in LineGeometry

    Link
    main.tpzReject untyped physical distances in LineGeometryOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.LineGeometry = ts.LineGeometry {
    3. bodyTarget: 24,
    4. firstTarget: 20,
    5. dropCapSpan: 0,
    6. dropCapInset: 0
    7. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:3:15
    Source evidence

    Use point lengths in PlanLine

    Link
    main.tpzUse point lengths in PlanLineOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.PlanLine = ts.PlanLine {
    3. start: 0,
    4. endExclusive: 1,
    5. trimmedEndExclusive: 1,
    6. displayTextScalarLength: 1,
    7. kind: ts.BreakKind.ForcedEnd(),
    8. target: 12pt,
    9. rawTextWidth: 10pt,
    10. trimmedTextWidth: 10pt,
    11. costTextWidth: 10pt,
    12. selectedPenaltyWidth: 0pt,
    13. postValidationWidthLimit: Some(13pt),
    14. cost: 0,
    15. adjustmentRatioR: 0
    16. }
    17. let distance: Length<Pt> = value.target
    18. let limit: Option<Length<Pt>> = value.postValidationWidthLimit
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject untyped physical distances in PlanLine

    Link
    main.tpzReject untyped physical distances in PlanLineOpen in Playground
    1. import std.typeset as ts
    2. let value: ts.PlanLine = ts.PlanLine {
    3. start: 0,
    4. endExclusive: 1,
    5. trimmedEndExclusive: 1,
    6. displayTextScalarLength: 1,
    7. kind: ts.BreakKind.ForcedEnd(),
    8. target: 12,
    9. rawTextWidth: 10,
    10. trimmedTextWidth: 10,
    11. costTextWidth: 10,
    12. selectedPenaltyWidth: 0,
    13. postValidationWidthLimit: Some(13),
    14. cost: 0,
    15. adjustmentRatioR: 0
    16. }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:8:11
    Source evidence

    Pass typed distances to the line-cost function

    Link
    main.tpzPass typed distances to the line-cost functionOpen in Playground
    1. import std.typeset as ts
    2. let value = ts.lineBadness(20pt, 20pt, 4, 1, ts.BreakKind.ForcedEnd(), false, 0, 0pt)
    Expected outputexit 0
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Checking accepts the program. Exit code 0.

    Source evidence

    Reject raw distances at the line-cost boundary

    Link
    main.tpzReject raw distances at the line-cost boundaryOpen in Playground
    1. import std.typeset as ts
    2. let value = ts.lineBadness(20, 20, 4, 1, ts.BreakKind.ForcedEnd(), false, 0, 0)
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during check. Nonzero exit.

    • TPZ5001 stdlib-physical-distance-requires-points at main.tpz:2:28
    Source evidence

    Diagnostics

    Link

    TPZ5001

    Compute fixed-point line badness from point lengths

    Link
    Ruletopaz.stdlib.contract.line-badness.rule

    Compute fixed-point line badness from point lengths

    lineBadness(width: Length<Pt>, target: Length<Pt>, charCount: int, spaces: int, kind: BreakKind, isLast: bool, justificationB: int, hyphenAdvance: Length<Pt>) -> Result<int, TypesetError> is the public entry point. lineBadnessMpt is absent and importing it is rejected with TPZ3009.

    The three distances require Length<Pt>. A raw scalar or another unit marker is rejected with TPZ5001. Width and hyphen advance may be negative. justificationB accepts every int and can make the resulting cost negative.

    Evaluate all eight argument expressions once in source order before entering the function. Convert width, target, and hyphenAdvance to millipoints in that order with the shared nearest-even rule.

    The converted target must be positive. charCount and spaces must each be nonnegative and need not satisfy a relation to each other. Invalid inputs return Err containing TypesetError.InvalidInput before cost arithmetic. The explanatory message text is not fixed.

    Let w, t, and h be the converted distances, c the character count, s the space count, and j the supplied justification cost. Let B be 1,000,000 and R be 100,000,000.

    For a nonnegative n and positive d, H gives n divided by d rounded to the nearest integer with ties upward. H describes cost rounding. Physical Length conversion keeps its separate nearest-even rule.

    The following sequence uses checked int operations in the stated order. A failing intermediate operation stops with runtime diagnostic TPZ4004. It does not return TypesetError or replace overflow with a bounded cost.

    Set effective to w + h for LatinSoftHyphen and to w for every other kind. Set slack to t - effective and absolute to the absolute value of slack.

    Set raw to 4 R when absolute is at least 4 t. Otherwise set raw to absolute * R / t with integer division. This explicit ratio cap does not change a supplied length.

    Set capacity to 100 + s * 45 when slack is nonnegative and to 100 + s * 25 otherwise. Set ratio = H(raw * 100, capacity), then q = H(ratio * ratio, R), then cost = H(q * (1000 * B), R).

    If isLast is true, replace cost with H(cost * 2, 5). Add 500 B when isLast is true and `w 100 < t * 52`. The strict comparison uses the original converted width and also applies when charCount is zero.

    If slack is negative, add 20000 * B + H(20000 * B * ratio, R). Add 65 B for LatinHyphen or LatinSoftHyphen. Add 50000 B for HardFallback. The other break kinds add no break penalty.

    If c is at most two, add 275 B. Then add 10 B and j in that order and return the result in Ok. The hyphenAdvance input affects width for LatinSoftHyphen and is ignored for the other kinds.

    An exact fit with more than two characters, no special break penalty, and zero justification cost returns 10000000. The documented 90 point line against a 100 point target with nine characters and two spaces returns 12770080.

    The function performs no I/O, changes no input, and reads no font, paragraph, or global grid state. Effects from argument evaluation remain visible on InvalidInput or a later arithmetic fault.

    An arithmetic fault identifies the public lineBadness call as its primary source location. Argument effects already performed remain visible and later expressions do not run.

    Why

    One typed entry point fixes the physical meaning before scoring a line. Explicit intermediate rounding makes costs reproducible. The same last-line width condition applies to every valid character count, including an empty line.

    Source evidence

    Compute a line cost from point lengths

    Link
    main.tpzCompute a line cost from point lengthsOpen in Playground
    1. import std.io
    2. import std.typeset as ts
    3. let cost = ts.lineBadness(20pt, 20pt, 4, 1, ts.BreakKind.ForcedEnd(), false, 0, 0pt)
    4. match (cost) {
    5. case Ok(value) => io.writeLine("{value}")
    6. case Err(_) => io.writeLine("unexpected input error")
    7. }
    Expected outputexit 0
    10000000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 10000000
    Source evidence

    Reject the former millipoint function name

    Link
    main.tpzReject the former millipoint function nameOpen in Playground
    1. import std.typeset { lineBadnessMpt }
    Expected outputNonzero exit
    No stdout.
    $ topaz check main.tpz --format json · target product 5.21.3
    Expected result

    Expected result

    Rejection during resolve. Nonzero exit.

    • TPZ3009 selected-name-not-exported at main.tpz:1:22
    Source evidence

    Preserve the published fixed-point costs

    Link
    main.tpzPreserve the published fixed-point costsOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. show(ts.lineBadness(100pt, 100pt, 10, 2, ts.BreakKind.LatinSpace(), false, 0, 0pt))
    9. show(ts.lineBadness(90pt, 100pt, 9, 2, ts.BreakKind.LatinSpace(), false, 0, 0pt))
    10. show(ts.lineBadness(100pt, 100pt, 10, 2, ts.BreakKind.LatinHyphen(), false, 0, 0pt))
    11. show(ts.lineBadness(40pt, 100pt, 4, 0, ts.BreakKind.ForcedEnd(), true, 0, 0pt))
    Expected outputexit 0
    10000000
    12770080
    75000000
    654000000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 10000000
    2. 12770080
    3. 75000000
    4. 654000000
    Source evidence

    Apply break penalties and the small character count boundary

    Link
    main.tpzApply break penalties and the small character count boundaryOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. show(ts.lineBadness(100pt, 100pt, 3, 0, ts.BreakKind.CjkCluster(), false, 0, 0pt))
    9. show(ts.lineBadness(100pt, 100pt, 3, 0, ts.BreakKind.ClosingPunctuation(), false, 0, 0pt))
    10. show(ts.lineBadness(100pt, 100pt, 3, 0, ts.BreakKind.HardFallback(), false, 0, 0pt))
    11. show(ts.lineBadness(100pt, 100pt, 2, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt))
    12. show(ts.lineBadness(99pt, 100pt, 9, 0, ts.BreakKind.LatinSoftHyphen(), false, 0, 1pt))
    13. show(ts.lineBadness(99pt, 100pt, 9, 0, ts.BreakKind.LatinHyphen(), false, 0, 1pt))
    Expected outputexit 0
    10000000
    10000000
    50010000000
    285000000
    75000000
    75100000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 10000000
    2. 10000000
    3. 50010000000
    4. 285000000
    5. 75000000
    6. 75100000
    Source evidence

    Use a strict last-line width threshold

    Link
    main.tpzUse a strict last-line width thresholdOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. show(ts.lineBadness(52pt, 100pt, 4, 0, ts.BreakKind.ForcedEnd(), true, 0, 0pt))
    9. show(ts.lineBadness(51pt, 100pt, 4, 0, ts.BreakKind.ForcedEnd(), true, 0, 0pt))
    Expected outputexit 0
    102160000
    606040000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 102160000
    2. 606040000
    Source evidence

    Apply the last-line width condition to zero characters

    Link
    main.tpzApply the last-line width condition to zero charactersOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. show(ts.lineBadness(0pt, 100pt, 0, 0, ts.BreakKind.ForcedEnd(), true, 0, 0pt))
    Expected outputexit 0
    1185000000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 1185000000
    Source evidence

    Keep signed inputs and cap the scoring ratio explicitly

    Link
    main.tpzKeep signed inputs and cap the scoring ratio explicitlyOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. show(ts.lineBadness(100pt, 100pt, 3, 0, ts.BreakKind.ForcedEnd(), false, -10000001, 0pt))
    9. show(ts.lineBadness(-1000pt, 100pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 0, -1pt))
    10. show(ts.lineBadness(500pt, 100pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt))
    11. show(ts.lineBadness(600pt, 100pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt))
    Expected outputexit 0
    -1
    16010000000
    116010000000
    116010000000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. -1
    2. 16010000000
    3. 116010000000
    4. 116010000000
    Source evidence

    Return InvalidInput for the target and count boundaries

    Link
    main.tpzReturn InvalidInput for the target and count boundariesOpen in Playground
    1. import std.typeset as ts
    2. import std.io
    3. for result in ([
    4. ts.lineBadness(1pt, 0pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt),
    5. ts.lineBadness(1pt, -1pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt),
    6. ts.lineBadness(1pt, 1pt, -1, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt),
    7. ts.lineBadness(1pt, 1pt, 3, -1, ts.BreakKind.ForcedEnd(), false, 0, 0pt)
    8. ]) {
    9. match (result) {
    10. case Err(InvalidInput(_)) => io.writeLine("invalid input")
    11. case _ => io.writeLine("unexpected result")
    12. }
    13. }
    Expected outputexit 0
    invalid input
    invalid input
    invalid input
    invalid input
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. invalid input
    2. invalid input
    3. invalid input
    4. invalid input
    Source evidence

    Validate target positivity after millipoint conversion

    Link
    main.tpzValidate target positivity after millipoint conversionOpen in Playground
    1. import std.typeset as ts
    2. import std.test
    3. import std.io
    4. function show(value: Result<int, ts.TypesetError>) -> () {
    5. let cost = test.assertOk(value)
    6. io.writeLine("{cost}")
    7. }
    8. let rejected = ts.lineBadness(0pt, ts.fromScaledPoints(32), 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt)
    9. match (rejected) {
    10. case Err(InvalidInput(_)) => io.writeLine("rounded target is zero")
    11. case _ => io.writeLine("unexpected result")
    12. }
    13. show(ts.lineBadness(ts.fromScaledPoints(33), ts.fromScaledPoints(33), 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt))
    14. show(ts.lineBadness(ts.fromScaledPoints(4096), ts.fromMilliPoints(62), 3, 0, ts.BreakKind.ForcedEnd(), false, 0, 0pt))
    Expected outputexit 0
    rounded target is zero
    10000000
    10000000
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. rounded target is zero
    2. 10000000
    3. 10000000
    Source evidence

    Evaluate every argument before input validation

    Link
    main.tpzEvaluate every argument before input validationOpen in Playground
    1. import std.typeset as ts
    2. import std.io
    3. function length(label: string, value: Length<Pt>) -> Length<Pt> {
    4. io.writeLine(label)
    5. value
    6. }
    7. function count(label: string, value: int) -> int {
    8. io.writeLine(label)
    9. value
    10. }
    11. function kind(value: ts.BreakKind) -> ts.BreakKind {
    12. io.writeLine("kind")
    13. value
    14. }
    15. function last(value: bool) -> bool {
    16. io.writeLine("last")
    17. value
    18. }
    19. let result = ts.lineBadness(
    20. length("width", 1pt), length("target", 0pt),
    21. count("chars", 3), count("spaces", 0),
    22. kind(ts.BreakKind.ForcedEnd()), last(false),
    23. count("justification", 0), length("hyphen", 0pt)
    24. )
    25. match (result) {
    26. case Err(InvalidInput(_)) => io.writeLine("invalid input")
    27. case _ => io.writeLine("unexpected result")
    28. }
    Expected outputexit 0
    width
    target
    chars
    spaces
    kind
    last
    justification
    hyphen
    invalid input
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. width
    2. target
    3. chars
    4. spaces
    5. kind
    6. last
    7. justification
    8. hyphen
    9. invalid input
    Source evidence

    Stop on checked cost overflow

    Link
    main.tpzStop on checked cost overflowOpen in Playground
    1. import std.typeset as ts
    2. ts.lineBadness(1pt, 1pt, 3, 0, ts.BreakKind.ForcedEnd(), false, 9223372036854775807, 0pt)
    Expected outputNonzero exit
    No stdout.
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Rejection during run. Nonzero exit.

    • TPZ4004 diagnostic-tpz4004 at main.tpz:2:1
    Source evidence

    Diagnostics

    Link

    Name is not exported

    Integer overflow

    Menu

    Download