From 20e36f83882ef04961756d86c02b5c7adf10885e Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 3 Feb 2025 10:55:43 -0500 Subject: [PATCH 01/18] Initial commit: TextMetrics additions --- source | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/source b/source index 13ac7862d0c..bb2dca9ecf1 100644 --- a/source +++ b/source @@ -4530,6 +4530,15 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute +
Unicode
+
+

The following terms are defined in Unicode: UNICODE

+ + +
+
Web App Manifest
@@ -65506,6 +65515,7 @@ interface mixin CanvasText { undefined fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); undefined strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); TextMetrics measureText(DOMString text); + undefined fillTextCluster(TextCluster textCluster, double x, double y, optional TextClusterOptions options); }; interface mixin CanvasDrawImage { @@ -65604,6 +65614,28 @@ interface TextMetrics { readonly attribute double hangingBaseline; readonly attribute double alphabeticBaseline; readonly attribute double ideographicBaseline; + + sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); + DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); + unsigned long getIndexFromOffset(double offset); + sequence<TextCluster> getTextClusters(unsigned long start, unsigned long end, optional TextClusterOptions options); +}; + +[Exposed=(Window,Worker)] +interface TextCluster { + readonly attribute double x; + readonly attribute double y; + readonly attribute unsigned long begin; + readonly attribute unsigned long end; + readonly attribute CanvasTextAlign align; + readonly attribute CanvasTextBaseline baseline; +}; + +dictionary TextClusterOptions { + CanvasTextAlign align; + CanvasTextBaseline baseline; + double x; + double y; }; dictionary ImageDataSettings { @@ -69143,6 +69175,12 @@ try {
metrics.ideographicBaseline

Returns the measurement described below.

+
metrics.getSelectionRects(start, end)
+
metrics.getActualBoundingBox(start, end)
+
metrics.getIndexFromOffset(offset)
+
metrics.getTextClusters(start, end [, options ])
+ +
context.fillTextCluster(textCluster, x, y [, options ])
@@ -69327,6 +69365,116 @@ try { positive numbers indicating that the given baseline is below the ideographic-under baseline. (Zero if the given baseline is the ideographic-under baseline.)

+ +
getSelectionRects(start, end) method
+ +

Returns the set of rectangles that the UA would render as selection to select + a particular character range, in CSS pixels. The positions are returned + relative to the alignment point given by the textAlign and textBaseline attributes.

+ +
getActualBoundingBox(start, end) method
+ +
+

Returns the rectangle equivalent to the box described by actualBoundingBoxLeft, actualBoundingBoxRight, actualBoundingBoxAscent, actualBoundingBoxDescent, for the given + range. The positions are returned relative to the alignment point given by the textAlign and textBaseline attributes.

+ +

The bounding box can be (and usually is) different from the selection + rectangles, which are based on the advance of the text. A font that is particularly slanted or + with accents that go beyond the flow of text will have a different paint bounding box.

+
+ +
getIndexFromOffset(offset) method
+ +

Returns the string index for the character at the given offset distance from the start + position of the text run, relative to the alignment point given by the textAlign attribute, with offset always increasing left + to right (negative offsets are valid). Values to the left or right of the text bounds will return + 0 or the length of the text, depending on the writing direction.

+ +
getTextClusters(start, end, options) method
+ +
+

Splits the given range of the text into grapheme clusters, and returns the positional data + for each cluster, as a list of new TextCluster objects, with members behaving as + described in the following list: UNICODE

+ +
+
x attribute
+ +
+

The x coordinate of the cluster, on a coordinate space using CSS pixels, with its origin at the anchor point defined by the textAlign attribute (at the time measureText() was called) in relation to the text + as a whole.

+ +

The x position specified for each cluster corresponds to the aligment point given by the + align attribute of the cluster (e.g. if + this attribute is set to "left", the calculated position corresponds + to the left of each cluster). The + selection criteria for this alignment point is explained in the section for this attribute + of the cluster.

+
+ +
y attribute
+ +
+

The y coordinate of the cluster, on a coordinate space using CSS pixels, with its origin at the anchor point defined by the textBaseline attribute (at the time measureText() was called) in relation to the text + as a whole.

+ +

The y position specified for each cluster corresponds to the aligment point given by the + baseline attribute of the cluster (e.g. if + this attribute is set to "top", the calculated position corresponds + to the top of each cluster). The + selection criteria for this alignment point is explained in the section for this attribute + of the cluster.

+
+ +
begin attribute
+ +

The starting index for the range of code points that are + rendered as this cluster.

+ +
end attribute
+ +

The ending index for the range of code points that are + rendered as this cluster.

+ +
align attribute
+ +

The align for the specific point returned for the cluster. If a + TextClusterOptions options dictionary is passed, and it has a value for + options.align, this will be the assigned value. Otherwise, it will be + set as the textAlign attribute. Note that this + doesn't change the origin of the coordinate system, just which point is specified for each + cluster.

+ +
baseline attribute
+ +

The baseline for the specific point returned for the cluster. If a + TextClusterOptions options dictionary is passed, and it has a value for + options.baseline, this will be the assigned value. Otherwise, it will + be set as the textBaseline attribute. Note + that this doesn't change the origin of the coordinate system, just which point is specified + for each cluster.

+
+ +

The user agent might internally store in the TextCluster object the + complete text, as well as all the CanvasTextDrawingStyles at the time that measureText() was called, as they will be needed to + correctly render the clusters as they were measured.

+

Glyphs rendered using fillText() and @@ -69339,7 +69487,67 @@ try { documents, rendered using CSS, straight to the canvas. This would be provided in preference to a dedicated way of doing multiline layout.

+

The fillTextCluster(textCluster, x, + y, options) method renders a TextCluster object. + The cluster is rendered where it would be if the whole text that was passed to measureText() to obtain the cluster was rendered at + position (x,y), unless the positioning is modified with the options + argument. Specifically, when the methods are invoked, the user agent must run these steps:

+ +
    +
  1. If any of the arguments are infinite or NaN, then return.

  2. + +
  3. Run the text preparation algorithm, passing it the text + originally passed to measureText() to obtain + the cluster, and an object with the CanvasTextDrawingStyles values as they were + when the cluster was measured, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let + glyphs be the result.

  4. + +
  5. Filter glyphs to include only glyphs that contain code points within the range cluster.begin to cluster.end.

  6. + +
  7. Move all the shapes in glyphs to the right by x + CSS pixels and down by y CSS + pixels.

  8. + +
  9. +

    If a TextClusterOptions options dictionary is passed and it has an options.x value, move all the shapes in glyphs to the right by + options.x-cluster.x.

    + +

    If a TextClusterOptions options dictionary is passed and it has an options.y value, move all the shapes in glyphs down by options.y-cluster.y.

    +
  10. + +
  11. +

    Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one + coordinate space unit.

    + +

    this's fill style must be applied to the + shapes and this's stroke style must be ignored. + +

    These shapes are painted without affecting the current path, and are subject to shadow effects, global + alpha, the clipping region, and the current compositing and blending + operator.

    +
  12. +
+

By setting options.x and options.y + to 0, the cluster will be rendered exactly at the position (x,y) passed to + fillTextCluster().

Drawing paths to the canvas
@@ -146080,6 +146288,7 @@ INSERT INTERFACES HERE Andreas Kling, Andrei Popescu, Andres Gomez, + Andrés Ricardo Pérez Rojas, Andres Rios, Andreu Botella, Andrew Barfield, From 370fb3cff0848ce80496ecf6935b7d8a02d303f4 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Fri, 7 Feb 2025 15:51:38 -0500 Subject: [PATCH 02/18] Group similar calls together, fix typos, and use infra maps --- source | 161 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/source b/source index bb2dca9ecf1..a19209d163e 100644 --- a/source +++ b/source @@ -65510,12 +65510,20 @@ interface mixin CanvasUserInterface { undefined drawFocusIfNeeded(Path2D path, Element element); }; + +dictionary TextClusterOptions { + CanvasTextAlign align; + CanvasTextBaseline baseline; + double x; + double y; +}; + interface mixin CanvasText { // text (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces) undefined fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); undefined strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); + undefined fillTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options); TextMetrics measureText(DOMString text); - undefined fillTextCluster(TextCluster textCluster, double x, double y, optional TextClusterOptions options); }; interface mixin CanvasDrawImage { @@ -65631,13 +65639,6 @@ interface TextCluster { readonly attribute CanvasTextBaseline baseline; }; -dictionary TextClusterOptions { - CanvasTextAlign align; - CanvasTextBaseline baseline; - double x; - double y; -}; - dictionary ImageDataSettings { PredefinedColorSpace colorSpace; }; @@ -69154,6 +69155,15 @@ try { provided, the text will be scaled to fit that width if necessary.

+
context.fillTextCluster(cluster, x, y [, options ])
+ +
+

Fills the given text cluster as it would be positioned if the text as a whole was rendered at + the given position. The align and baseline used to render, as well as the position of the + cluster in relation to the anchor point of the while text, can be modified with the options + dictionary.

+
+
metrics = context.measureText(text)
@@ -69179,8 +69189,6 @@ try {
metrics.getActualBoundingBox(start, end)
metrics.getIndexFromOffset(offset)
metrics.getTextClusters(start, end [, options ])
- -
context.fillTextCluster(textCluster, x, y [, options ])
@@ -69234,6 +69242,69 @@ try { +

The fillTextCluster(cluster, x, + y, options) method renders a TextCluster object. + The cluster is rendered where it would be if the whole text that was passed to measureText() to obtain the cluster was rendered at + position (x,y), unless the positioning is modified with the options + argument. Specifically, when the method is invoked, the user agent must run these steps:

+ +
    +
  1. If any of the arguments are infinite or NaN, then return.

  2. + +
  3. Run the text preparation algorithm, passing it the text + originally passed to measureText() to obtain + the cluster, and an object with the CanvasTextDrawingStyles values as they were + when the cluster was measured, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let + glyphs be the result.

  4. + +
  5. Filter glyphs to include only the glyphs that contain code points within the range cluster["begin"] to cluster["end"].

  6. + +
  7. Move all the shapes in glyphs to the right by x + CSS pixels and down by y CSS + pixels.

  8. + +
  9. +

    If a TextClusterOptions options dictionary is passed and it has an options["x"] value, move all the shapes in glyphs to the right by + options["x"] − cluster["x"].

    + +

    If a TextClusterOptions options dictionary is passed and it has an options["y"] value, move all the shapes in glyphs down by options["y"] − cluster["y"].

    +
  10. + +
  11. +

    Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one + coordinate space unit.

    + +

    this's fill style must be applied to the + shapes and this's stroke style must be ignored. + +

    These shapes are painted without affecting the current path, and are subject to shadow effects, global + alpha, the clipping region, and the current compositing and blending + operator.

    +
  12. +
+ +

By setting options["x"] and options["y"] to 0, the cluster will be rendered exactly at the position + (x,y) passed to fillTextCluster().

+

The measureText() was called) in relation to the text as a whole.

-

The x position specified for each cluster corresponds to the aligment point given by the +

The x position specified for each cluster corresponds to the alignment point given by the align attribute of the cluster (e.g. if this attribute is set to "left", the calculated position corresponds to the left of each cluster). The @@ -69433,7 +69504,7 @@ try { data-x="dom-context-2d-measureText">measureText() was called) in relation to the text as a whole.

-

The y position specified for each cluster corresponds to the aligment point given by the +

The y position specified for each cluster corresponds to the alignment point given by the baseline attribute of the cluster (e.g. if this attribute is set to "top", the calculated position corresponds to the top of each cluster). The @@ -69455,7 +69526,7 @@ try {

The align for the specific point returned for the cluster. If a TextClusterOptions options dictionary is passed, and it has a value for - options.align, this will be the assigned value. Otherwise, it will be + options["align"], this will be the assigned value. Otherwise, it will be set as the textAlign attribute. Note that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

@@ -69464,7 +69535,7 @@ try {

The baseline for the specific point returned for the cluster. If a TextClusterOptions options dictionary is passed, and it has a value for - options.baseline, this will be the assigned value. Otherwise, it will + options["baseline"], this will be the assigned value. Otherwise, it will be set as the textBaseline attribute. Note that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

@@ -69487,68 +69558,6 @@ try { documents, rendered using CSS, straight to the canvas. This would be provided in preference to a dedicated way of doing multiline layout.

-

The fillTextCluster(textCluster, x, - y, options) method renders a TextCluster object. - The cluster is rendered where it would be if the whole text that was passed to measureText() to obtain the cluster was rendered at - position (x,y), unless the positioning is modified with the options - argument. Specifically, when the methods are invoked, the user agent must run these steps:

- -
    -
  1. If any of the arguments are infinite or NaN, then return.

  2. - -
  3. Run the text preparation algorithm, passing it the text - originally passed to measureText() to obtain - the cluster, and an object with the CanvasTextDrawingStyles values as they were - when the cluster was measured, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let - glyphs be the result.

  4. - -
  5. Filter glyphs to include only glyphs that contain code points within the range cluster.begin to cluster.end.

  6. - -
  7. Move all the shapes in glyphs to the right by x - CSS pixels and down by y CSS - pixels.

  8. - -
  9. -

    If a TextClusterOptions options dictionary is passed and it has an options.x value, move all the shapes in glyphs to the right by - options.x-cluster.x.

    - -

    If a TextClusterOptions options dictionary is passed and it has an options.y value, move all the shapes in glyphs down by options.y-cluster.y.

    -
  10. - -
  11. -

    Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one - coordinate space unit.

    - -

    this's fill style must be applied to the - shapes and this's stroke style must be ignored. - -

    These shapes are painted without affecting the current path, and are subject to shadow effects, global - alpha, the clipping region, and the current compositing and blending - operator.

    -
  12. -
- -

By setting options.x and options.y - to 0, the cluster will be rendered exactly at the position (x,y) passed to - fillTextCluster().

-
Drawing paths to the canvas

Objects that implement the CanvasDrawPath interface have a current default From 1f94348d1bb334c2776c6655e0fb9032c0f97839 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 10 Feb 2025 11:48:25 -0500 Subject: [PATCH 03/18] Clarify index inclusion for ranges --- source | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/source b/source index a19209d163e..4c4a497e47e 100644 --- a/source +++ b/source @@ -69439,10 +69439,11 @@ try {

getSelectionRects(start, end) method
-

Returns the set of rectangles that the UA would render as selection to select - a particular character range, in CSS pixels. The positions are returned - relative to the alignment point given by the textAlign and

Returns the set of rectangles, in CSS pixels, that the user + agent would render as a selection to select the characters within the specified range. The + range includes the character at the start index but stops before the end + index. The positions are returned relative to the alignment point given by the + textAlign and textBaseline attributes.

getActualBoundingBox(start, end) method
@@ -69453,8 +69454,9 @@ try { data-x="dom-textmetrics-actualBoundingBoxRight">actualBoundingBoxRight
, actualBoundingBoxAscent, actualBoundingBoxDescent, for the given - range. The positions are returned relative to the alignment point given by the textAlign and start index but stops before the + end index. The positions are returned relative to the alignment point given by the + textAlign and textBaseline attributes.

The bounding box can be (and usually is) different from the selection @@ -69473,9 +69475,11 @@ try {

getTextClusters(start, end, options) method
-

Splits the given range of the text into grapheme clusters, and returns the positional data - for each cluster, as a list of new TextCluster objects, with members behaving as - described in the following list: UNICODE

+

Splits the given range of the text into grapheme clusters, and returns the positional data for each + cluster. The range includes the character at the start index but stops before the + end index. The result is a list of new TextCluster objects with members + behaving as described in the following list: UNICODE

x attribute
@@ -69519,8 +69523,8 @@ try {
end attribute
-

The ending index for the range of code points that are - rendered as this cluster.

+

The index immediately after the last included index for the range of code points that are rendered as this cluster.

align attribute
From 1b9e7358ef079abe4217efaa3d088ff8ecee26be Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 10 Feb 2025 13:54:08 -0500 Subject: [PATCH 04/18] Add strokeTextCluster() --- source | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/source b/source index 4c4a497e47e..439c5a30a82 100644 --- a/source +++ b/source @@ -65523,6 +65523,7 @@ interface mixin CanvasText { undefined fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); undefined strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); undefined fillTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options); + undefined strokeTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options); TextMetrics measureText(DOMString text); }; @@ -69156,12 +69157,13 @@ try {
context.fillTextCluster(cluster, x, y [, options ])
+
context.strokeTextCluster(cluster, x, y [, options ])
-

Fills the given text cluster as it would be positioned if the text as a whole was rendered at - the given position. The align and baseline used to render, as well as the position of the - cluster in relation to the anchor point of the while text, can be modified with the options - dictionary.

+

Fills or strokes (respectively) the given text cluster as it would be positioned if the text + as a whole was rendered at the given position. The align and baseline used to render, as well as + the position of the cluster in relation to the anchor point of the while text, can be modified + with the options dictionary.

metrics = context.measureText(text)
@@ -69244,7 +69246,9 @@ try {

The fillTextCluster(cluster, x, - y, options) method renders a TextCluster object. + y, options) and strokeTextCluster(cluster, x, + y, options) methods render a TextCluster object. The cluster is rendered where it would be if the whole text that was passed to measureText() to obtain the cluster was rendered at position (x,y), unless the positioning is modified with the options @@ -69288,10 +69292,16 @@ try { data-x="'px'">CSS pixel in the coordinate space of glyphs mapped to one coordinate space unit.

-

this's fill style must be applied to the - shapes and this's stroke style must be ignored. +

For fillTextCluster(), + this's fill style + must be applied to the shapes and this's stroke style must be ignored. For + strokeTextCluster(), the reverse holds: + this's stroke + style must be applied to the result of tracing the + shapes using the object implementing the CanvasText interface for the line + styles, and this's fill + style must be ignored.

These shapes are painted without affecting the current path, and are subject to shadow effects, global @@ -69303,7 +69313,8 @@ try {

By setting options["x"] and options["y"] to 0, the cluster will be rendered exactly at the position (x,y) passed to fillTextCluster().

+ data-x="dom-context-2d-fillTextCluster">fillTextCluster() and strokeTextCluster().

From 9cab38c37216f7104a8444c779944bf42b5200c1 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Wed, 12 Feb 2025 12:38:10 -0500 Subject: [PATCH 05/18] Make TextCluster an opaque object --- source | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/source b/source index 439c5a30a82..a1b10011bac 100644 --- a/source +++ b/source @@ -65632,6 +65632,7 @@ interface TextMetrics { [Exposed=(Window,Worker)] interface TextCluster { + // opaque object readonly attribute double x; readonly attribute double y; readonly attribute unsigned long begin; @@ -69257,10 +69258,9 @@ try {

  1. If any of the arguments are infinite or NaN, then return.

  2. -
  3. Run the text preparation algorithm, passing it the text - originally passed to measureText() to obtain - the cluster, and an object with the CanvasTextDrawingStyles values as they were - when the cluster was measured, with the exception of

    Run the text preparation algorithm, passing it the complete text and the + CanvasTextDrawingStyles from the opaque TextCluster + cluster, with the exception of textAlign and textBaseline, which are taken from the align and Splits the given range of the text into grapheme clusters, and returns the positional data for each cluster. The range includes the character at the start index but stops before the - end index. The result is a list of new TextCluster objects with members - behaving as described in the following list: UNICODE

    + end index. The result is a list of new TextCluster objects. These + objects are opaque as they encapsulate the complete text that was segmented, along with the + CanvasTextDrawingStyles values that were active at the time measureText() was called. Note that textAlign and + textBaseline are exceptions, as they are explicitly set attributes and are handled separately. Each + TextCluster object has members behaving as described in the following list: + UNICODE

    x attribute
    @@ -69555,11 +69561,6 @@ try { that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

    - -

    The user agent might internally store in the TextCluster object the - complete text, as well as all the CanvasTextDrawingStyles at the time that measureText() was called, as they will be needed to - correctly render the clusters as they were measured.

    From 85c06f16b2ed50cee09e6e4dd5972e1fbbf71a40 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Wed, 12 Feb 2025 15:06:30 -0500 Subject: [PATCH 06/18] Fix indentantion around getTextClusters --- source | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/source b/source index a1b10011bac..628cf56abbe 100644 --- a/source +++ b/source @@ -69473,19 +69473,19 @@ try {

    The bounding box can be (and usually is) different from the selection rectangles, which are based on the advance of the text. A font that is particularly slanted or with accents that go beyond the flow of text will have a different paint bounding box.

    - + -
    getIndexFromOffset(offset) method
    +
    getIndexFromOffset(offset) method
    -

    Returns the string index for the character at the given offset distance from the start - position of the text run, relative to the alignment point given by the textAlign attribute, with offset always increasing left - to right (negative offsets are valid). Values to the left or right of the text bounds will return - 0 or the length of the text, depending on the writing direction.

    +

    Returns the string index for the character at the given offset distance from the start + position of the text run, relative to the alignment point given by the textAlign attribute, with offset always increasing left + to right (negative offsets are valid). Values to the left or right of the text bounds will return + 0 or the length of the text, depending on the writing direction.

    -
    getTextClusters(start, end, options) method
    +
    getTextClusters(start, end, options) method
    -
    +

    Splits the given range of the text into grapheme clusters, and returns the positional data for each cluster. The range includes the character at the start index but stops before the @@ -69561,7 +69561,7 @@ try { that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

    - +

    Glyphs rendered using fillText() and From b6a2c7a150c058ab6fd19bab0c0b107f65d75961 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Fri, 14 Feb 2025 18:36:39 -0500 Subject: [PATCH 07/18] Add description for new methods in intro section --- source | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/source b/source index 628cf56abbe..800fa3c22a2 100644 --- a/source +++ b/source @@ -4165,6 +4165,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute x and y members

  4. Matrix multiplication
  5. +
  6. DOMRectReadOnly and DOMRect
  7. The following terms are defined in the CSS Scoping: CSSSCOPING

    @@ -65624,8 +65625,8 @@ interface TextMetrics { readonly attribute double alphabeticBaseline; readonly attribute double ideographicBaseline; - sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); - DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); + sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); + DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); unsigned long getIndexFromOffset(double offset); sequence<TextCluster> getTextClusters(unsigned long start, unsigned long end, optional TextClusterOptions options); }; @@ -69188,10 +69189,27 @@ try {
    metrics.ideographicBaseline

    Returns the measurement described below.

    +
    metrics.getSelectionRects(start, end)
    + +

    Returns a list of DOMRectReadOnly objects corresponding to the selection + rectangles for the given range in the string.

    +
    metrics.getActualBoundingBox(start, end)
    + +

    Returns a DOMRectReadOnly that corresponds to the bounding rectangle for the + given range in the string.

    +
    metrics.getIndexFromOffset(offset)
    + +

    Returns the index for the character at the given offset from the start of the text.

    +
    metrics.getTextClusters(start, end [, options ])
    + +

    Returns a list of TextCluster objects, with positional data for each one. + They correspond to splitting the text into the minimal rendering units possible. The options + dictionary enables selecting a specific point to be returned for each cluster be specifying align + and baseline values.

    From 6e08c935dc7797a501c634cbd06f108b7868dddb Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Tue, 18 Feb 2025 16:01:21 -0500 Subject: [PATCH 08/18] Clarify cluster definition --- source | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/source b/source index 800fa3c22a2..40056f05ab2 100644 --- a/source +++ b/source @@ -4531,15 +4531,6 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute -
    Unicode
    -
    -

    The following terms are defined in Unicode: UNICODE

    - -
      -
    • grapheme cluster
    • -
    -
    -
    Web App Manifest
    @@ -69504,17 +69495,21 @@ try {
    getTextClusters(start, end, options) method
    -

    Splits the given range of the text into grapheme clusters, and returns the positional data for each - cluster. The range includes the character at the start index but stops before the - end index. The result is a list of new TextCluster objects. These - objects are opaque as they encapsulate the complete text that was segmented, along with the +

    Splits the given range of the text into clusters and returns the positional data for each + cluster. The range includes the character at the start index but stops before the + end index. Each cluster represents a minimal group of characters such that their + corresponding glyphs cannot be broken down any further, and each character in the range is part + of only one cluster. If a cluster is only partially contained by the given character range, it + should still be included in the returned list.

    + +

    The result is a list of new TextCluster objects. These objects are opaque as + they encapsulate the complete text that was segmented, along with the CanvasTextDrawingStyles values that were active at the time measureText() was called. Note that textAlign and - textBaseline are exceptions, as they are explicitly set attributes and are handled separately. Each - TextCluster object has members behaving as described in the following list: - UNICODE

    + data-x="dom-context-2d-textAlign">textAlign
    and textBaseline are exceptions, as they are explicitly + set attributes and are handled separately. Each TextCluster object has members + behaving as described in the following list:

    x attribute
    From a20a528a04821f87a2b19fca258be570b8144e7d Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Fri, 28 Feb 2025 15:14:59 -0500 Subject: [PATCH 09/18] Formatting and DOMRect references --- source | 102 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/source b/source index 40056f05ab2..ae20de4a358 100644 --- a/source +++ b/source @@ -4165,7 +4165,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute x and y members
  8. Matrix multiplication
  9. -
  10. DOMRectReadOnly and DOMRect
  11. +
  12. DOMRectReadOnly
  13. The following terms are defined in the CSS Scoping: CSSSCOPING

    @@ -65616,8 +65616,8 @@ interface TextMetrics { readonly attribute double alphabeticBaseline; readonly attribute double ideographicBaseline; - sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); - DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); + sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); + DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); unsigned long getIndexFromOffset(double offset); sequence<TextCluster> getTextClusters(unsigned long start, unsigned long end, optional TextClusterOptions options); }; @@ -69183,12 +69183,12 @@ try {
    metrics.getSelectionRects(start, end)
    -

    Returns a list of DOMRectReadOnly objects corresponding to the selection +

    Returns a list of DOMRectReadOnly objects corresponding to the selection rectangles for the given range in the string.

    metrics.getActualBoundingBox(start, end)
    -

    Returns a DOMRectReadOnly that corresponds to the bounding rectangle for the +

    Returns a DOMRectReadOnly that corresponds to the bounding rectangle for the given range in the string.

    metrics.getIndexFromOffset(offset)
    @@ -69265,58 +69265,58 @@ try { argument. Specifically, when the method is invoked, the user agent must run these steps:

      -
    1. If any of the arguments are infinite or NaN, then return.

    2. +
    3. If any of the arguments are infinite or NaN, then return.

    4. -
    5. Run the text preparation algorithm, passing it the complete text and the - CanvasTextDrawingStyles from the opaque TextCluster - cluster, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let - glyphs be the result.

    6. +
    7. Run the text preparation algorithm, passing it the complete text and the + CanvasTextDrawingStyles from the opaque TextCluster + cluster, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let + glyphs be the result.

    8. -
    9. Filter glyphs to include only the glyphs that contain code points within the range cluster["begin"] to cluster["end"].

    10. +
    11. Filter glyphs to include only the glyphs that contain code points within the range cluster["begin"] to cluster["end"].

    12. -
    13. Move all the shapes in glyphs to the right by x - CSS pixels and down by y CSS - pixels.

    14. +
    15. Move all the shapes in glyphs to the right by x + CSS pixels and down by y CSS + pixels.

    16. -
    17. -

      If a TextClusterOptions options dictionary is passed and it has an options["x"] value, move all the shapes in glyphs to the right by - options["x"] − cluster["x"].

      +
    18. +

      If a TextClusterOptions options dictionary is passed and it has an options["x"] value, move all the shapes in glyphs to the right by + options["x"] − cluster["x"].

      -

      If a TextClusterOptions options dictionary is passed and it has an options["y"] value, move all the shapes in glyphs down by options["y"] − cluster["y"].

      -
    19. +

      If a TextClusterOptions options dictionary is passed and it has an options["y"] value, move all the shapes in glyphs down by options["y"] − cluster["y"].

      + -
    20. -

      Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one - coordinate space unit.

      - -

      For fillTextCluster(), - this's fill style - must be applied to the shapes and this's stroke style must be ignored. For - strokeTextCluster(), the reverse holds: - this's stroke - style must be applied to the result of tracing the - shapes using the object implementing the CanvasText interface for the line - styles, and this's fill - style must be ignored.

      - -

      These shapes are painted without affecting the current path, and are subject to shadow effects, global - alpha, the clipping region, and the current compositing and blending - operator.

      -
    21. +
    22. +

      Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one + coordinate space unit.

      + +

      For fillTextCluster(), + this's fill style + must be applied to the shapes and this's stroke style must be ignored. For + strokeTextCluster(), the reverse holds: + this's stroke + style must be applied to the result of tracing the + shapes using the object implementing the CanvasText interface for the line + styles, and this's fill + style must be ignored.

      + +

      These shapes are painted without affecting the current path, and are subject to shadow effects, global + alpha, the clipping region, and the current compositing and blending + operator.

      +

    By setting options["x"] and Date: Fri, 28 Feb 2025 16:05:12 -0500 Subject: [PATCH 10/18] Modern phrasing for fill/strokeTextCluster() --- source | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source b/source index ae20de4a358..21670b366cb 100644 --- a/source +++ b/source @@ -69258,11 +69258,7 @@ try { data-x="dom-context-2d-fillTextCluster">fillTextCluster(cluster, x, y, options) and strokeTextCluster(cluster, x, - y, options) methods render a TextCluster object. - The cluster is rendered where it would be if the whole text that was passed to measureText() to obtain the cluster was rendered at - position (x,y), unless the positioning is modified with the options - argument. Specifically, when the method is invoked, the user agent must run these steps:

    + y, options)
    methods, when invoked, must run these steps:

    1. If any of the arguments are infinite or NaN, then return.

    2. From 8062ab076a2a279912adcface1a437fbaee047df Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 3 Mar 2025 17:24:54 -0500 Subject: [PATCH 11/18] Rename TextCluster begin attribute to start --- source | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source b/source index 21670b366cb..ca2dae1fdf8 100644 --- a/source +++ b/source @@ -65627,7 +65627,7 @@ interface TextCluster { // opaque object readonly attribute double x; readonly attribute double y; - readonly attribute unsigned long begin; + readonly attribute unsigned long start; readonly attribute unsigned long end; readonly attribute CanvasTextAlign align; readonly attribute CanvasTextBaseline baseline; @@ -69274,7 +69274,7 @@ try {
    3. Filter glyphs to include only the glyphs that contain code points within the range cluster["begin"] to cluster["start"] to cluster["end"].

    4. Move all the shapes in glyphs to the right by x @@ -69542,7 +69542,7 @@ try { of the cluster.

    -
    begin attribute
    +
    start attribute

    The starting index for the range of code points that are rendered as this cluster.

    From 1f8aa8fbd1c918db0dbd50783b77956c343ce3df Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Thu, 6 Mar 2025 10:22:17 -0500 Subject: [PATCH 12/18] Modern phrasing for getSelectionRects() and getActualBoundingBox() --- source | 68 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/source b/source index ca2dae1fdf8..bd0e5fc9c6e 100644 --- a/source +++ b/source @@ -69453,27 +69453,53 @@ try { baseline. (Zero if the given baseline is the ideographic-under baseline.)

    -
    getSelectionRects(start, end) method
    - -

    Returns the set of rectangles, in CSS pixels, that the user - agent would render as a selection to select the characters within the specified range. The - range includes the character at the start index but stops before the end - index. The positions are returned relative to the alignment point given by the - textAlign and textBaseline attributes.

    - -
    getActualBoundingBox(start, end) method
    - -
    -

    Returns the rectangle equivalent to the box described by actualBoundingBoxLeft, actualBoundingBoxRight, actualBoundingBoxAscent, actualBoundingBoxDescent, for the given - range. The range includes the character at the start index but stops before the - end index. The positions are returned relative to the alignment point given by the - textAlign and textBaseline attributes.

    +
    The getSelectionRects(start, end) method, when invoked, must run these steps:
    + +
    +
      +
    1. If either start or end are less than 0, start is + greater or equal than the number of code points in the + measured text, or end is greater than the number of code points in the measured text, then throw an + "IndexSizeError" DOMException.

    2. + +
    3. Let element be inline box returned by the + text preparation algorithm when measureText() was called.

    4. + +
    5. Let rects be a list of DOMRectReadOnly objects.

    6. + +
    7. Fill rects with the selection rectangles the user agent would render if the + selection was set to a range in + element, with the first included code point at the startth + position (in logical order) and the last included code point at the (end-1)th + position.

    8. + +
    9. Return rects.

    10. +
    +
    + +
    The getActualBoundingBox(start, end) method, when invoked, must run these steps:
    + +
    +
      +
    1. If either start or end are less than 0, start is + greater or equal than the number of code points in the + measured text, or end is greater than the number of code points in the measured text, then throw an + "IndexSizeError" DOMException.

    2. + +
    3. Let glyphs be the result of the + text preparation algorithm when measureText() was called.

    4. + +
    5. Filter glyphs to include only the glyphs that contain code points within the range that includes the start + index but stops before the end index.

    6. + +
    7. Return a DOMRectReadOnly representing the bounding box of + glyphs.

    8. +

    The bounding box can be (and usually is) different from the selection rectangles, which are based on the advance of the text. A font that is particularly slanted or From b7072166f650042c739b0aebfe8d8c6df76a59f0 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Tue, 11 Mar 2025 16:00:13 -0400 Subject: [PATCH 13/18] Fix reference link, add dfn, and minor fixes --- source | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/source b/source index bd0e5fc9c6e..da07f209133 100644 --- a/source +++ b/source @@ -4165,7 +4165,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute x and y members

  14. Matrix multiplication
  15. -
  16. DOMRectReadOnly
  17. +
  18. DOMRectReadOnly
  19. The following terms are defined in the CSS Scoping: CSSSCOPING

    @@ -65504,18 +65504,18 @@ interface mixin CanvasUserInterface { dictionary TextClusterOptions { - CanvasTextAlign align; - CanvasTextBaseline baseline; - double x; - double y; + CanvasTextAlign align; + CanvasTextBaseline baseline; + double x; + double y; }; interface mixin CanvasText { // text (see also the CanvasPathDrawingStyles and CanvasTextDrawingStyles interfaces) undefined fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); undefined strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); - undefined fillTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options); - undefined strokeTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options); + undefined fillTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options = {}); + undefined strokeTextCluster(TextCluster cluster, double x, double y, optional TextClusterOptions options = {}); TextMetrics measureText(DOMString text); }; @@ -69283,12 +69283,16 @@ try {
  20. If a TextClusterOptions options dictionary is passed and it has an options["x"] value, move all the shapes in glyphs to the right by - options["x"] − cluster["x"].

    + data-x="dom-TextClusterOptions-x">options["x"] value, move all the shapes in + glyphs to the right by options["x"]cluster["x"].

    If a TextClusterOptions options dictionary is passed and it has an options["y"] value, move all the shapes in glyphs down by options["y"] − cluster["y"].

    + data-x="dom-TextClusterOptions-y">options["y"] value, move all the shapes in + glyphs down by options["y"]cluster["y"].

  21. @@ -69453,7 +69457,7 @@ try { baseline. (Zero if the given baseline is the ideographic-under baseline.)

  22. -
    The getSelectionRects(start, end) method, when invoked, must run these steps:
    +
    The getSelectionRects(start, end) method steps are:
      @@ -69479,7 +69483,7 @@ try {
    -
    The getActualBoundingBox(start, end) method, when invoked, must run these steps:
    +
    The getActualBoundingBox(start, end) method steps are:
      @@ -69582,19 +69586,20 @@ try {

      The align for the specific point returned for the cluster. If a TextClusterOptions options dictionary is passed, and it has a value for - options["align"], this will be the assigned value. Otherwise, it will be - set as the textAlign attribute. Note that this - doesn't change the origin of the coordinate system, just which point is specified for each - cluster.

      + options["align"], this will be the assigned + value. Otherwise, it will be set as the textAlign attribute. Note that this doesn't change + the origin of the coordinate system, just which point is specified for each cluster.

    baseline attribute

    The baseline for the specific point returned for the cluster. If a TextClusterOptions options dictionary is passed, and it has a value for - options["baseline"], this will be the assigned value. Otherwise, it will - be set as the textBaseline attribute. Note - that this doesn't change the origin of the coordinate system, just which point is specified - for each cluster.

    + options["baseline"], this will be the + assigned value. Otherwise, it will be set as the textBaseline attribute. Note that this doesn't + change the origin of the coordinate system, just which point is specified for each cluster. +

    @@ -69609,6 +69614,8 @@ try { documents, rendered using CSS, straight to the canvas. This would be provided in preference to a dedicated way of doing multiline layout.

    + +
    Drawing paths to the canvas

    Objects that implement the CanvasDrawPath interface have a current default From 876d402a7331354c317e528c5be48eae8e348e89 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Thu, 13 Mar 2025 17:23:32 -0400 Subject: [PATCH 14/18] Reorganize TextCluster rendering --- source | 124 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/source b/source index da07f209133..3af2d8d47e0 100644 --- a/source +++ b/source @@ -69254,74 +69254,88 @@ try {

+

A canvas fill-stroke mode is an enum that describes whether the rendered text will + be filled or stroked:

+ +
+
fill
+

The shapes are filled using this's fill style.

+ +
stroke
+

The shapes are traced using this's stroke style.

+
+

The fillTextCluster(cluster, x, - y, options) and y, options) method steps are to call the cluster + rendering algorithm, passing it cluster, x, y, + options, and the fill canvas + fill-stroke mode enum.

+ +

The strokeTextCluster(cluster, x, - y, options) methods, when invoked, must run these steps:

+ y, options) method steps are to call the cluster + rendering algorithm, passing it cluster, x, y, + options, and the stroke canvas + fill-stroke mode enum.

+ +

The cluster rendering algorithm is as follows. It takes as input a + TextCluster cluster, a double x, a double y, a + TextClusterOptions options, and a canvas fill-stroke mode + mode.

    -
  1. If any of the arguments are infinite or NaN, then return.

  2. +
  3. If the x or the y arguments are infinite or NaN, then return.

    +
  4. Run the text preparation algorithm, passing it the complete text and the CanvasTextDrawingStyles from the opaque TextCluster - cluster, with the exception of textAlign and textBaseline, which are taken from the align and baseline attributes of cluster. Let - glyphs be the result.

  5. - -
  6. Filter glyphs to include only the glyphs that contain code points within the range cluster["start"] to cluster["end"].

  7. + cluster. Let glyphs be the result.

    + +
  8. Filter glyphs to include only the glyphs that correspond to code points within the range cluster["start"] to cluster["end"].

  9. Move all the shapes in glyphs to the right by x CSS pixels and down by y CSS pixels.

  10. -

    If a TextClusterOptions options dictionary is passed and it has an options["x"] value, move all the shapes in - glyphs to the right by options["x"]cluster["x"].

    +

    If options["x"] exists, move all the shapes in glyphs to the right by + options["x"] − + cluster["x"].

    -

    If a TextClusterOptions options dictionary is passed and it has an options["y"] value, move all the shapes in - glyphs down by options["y"]cluster["y"].

    +

    If options["y"] exists, move all the shapes in glyphs to the right by + options["y"] − + cluster["y"].

  11. -
  12. -

    Paint the shapes given in glyphs, as transformed by the current transformation matrix, with each CSS pixel in the coordinate space of glyphs mapped to one - coordinate space unit.

    +
  13. If mode is fill, let + shapes be the result of applying this's fill style to the shapes given in + glyphs.

  14. -

    For fillTextCluster(), - this's fill style - must be applied to the shapes and this's stroke style must be ignored. For - strokeTextCluster(), the reverse holds: - this's stroke - style must be applied to the result of tracing the - shapes using the object implementing the CanvasText interface for the line - styles, and this's fill - style must be ignored.

    +
  15. Otherwise, if mode is stroke, let shapes be the result of + applying this's stroke style to the result of tracing the shapes given in glyphs using the object + implementing the CanvasText interface for the line styles.

  16. -

    These shapes are painted without affecting the current path, and are subject to shadow effects, global - alpha, the clipping region, and the current compositing and blending - operator.

    - +
  17. Paint shapes without affecting the current path, and subject to shadow effects, global + alpha, the clipping region, and the current compositing and blending + operator.

-

By setting options["x"] and options["y"] to 0, the cluster will be rendered exactly at the position - (x,y) passed to By setting options["x"] + and options["y"] to 0, the cluster will + be rendered exactly at the position (x,y) passed to fillTextCluster() and strokeTextCluster().

@@ -69497,7 +69511,7 @@ try { text preparation algorithm when measureText() was called.

-
  • Filter glyphs to include only the glyphs that contain

    Filter glyphs to include only the glyphs that correspond to code points within the range that includes the start index but stops before the end index.

  • @@ -69584,19 +69598,17 @@ try {
    align attribute
    -

    The align for the specific point returned for the cluster. If a - TextClusterOptions options dictionary is passed, and it has a value for - options["align"], this will be the assigned - value. Otherwise, it will be set as the

    The align for the specific point returned for the cluster. Let it be + options["align"] if it exists; otherwise, the textAlign attribute. Note that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

    baseline attribute
    -

    The baseline for the specific point returned for the cluster. If a - TextClusterOptions options dictionary is passed, and it has a value for - options["baseline"], this will be the - assigned value. Otherwise, it will be set as the

    The baseline for the specific point returned for the cluster. Let it be + options["baseline"] if it + exists; otherwise, the textBaseline attribute. Note that this doesn't change the origin of the coordinate system, just which point is specified for each cluster.

    From 9ba74f53a6032bd8f1e4d59157d382c6737671c1 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Fri, 14 Mar 2025 20:19:39 -0400 Subject: [PATCH 15/18] Modern phrasing for getTextCluster() --- source | 100 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/source b/source index 3af2d8d47e0..65f6026361f 100644 --- a/source +++ b/source @@ -69532,29 +69532,43 @@ try { to right (negative offsets are valid). Values to the left or right of the text bounds will return 0 or the length of the text, depending on the writing direction.

    -
    getTextClusters(start, end, options) method
    +
    The getTextClusters(start, end, options) method steps are:
    -

    Splits the given range of the text into clusters and returns the positional data for each - cluster. The range includes the character at the start index but stops before the - end index. Each cluster represents a minimal group of characters such that their - corresponding glyphs cannot be broken down any further, and each character in the range is part - of only one cluster. If a cluster is only partially contained by the given character range, it - should still be included in the returned list.

    +
      +
    1. If either start or end are less than 0, start is + greater or equal than the number of code points in the + measured text, or end is greater than the number of code points in the measured text, then throw an + "IndexSizeError" DOMException.

    2. -

      The result is a list of new TextCluster objects. These objects are opaque as - they encapsulate the complete text that was segmented, along with the - CanvasTextDrawingStyles values that were active at the time measureText() was called. Note that textAlign and textBaseline are exceptions, as they are explicitly - set attributes and are handled separately. Each TextCluster object has members - behaving as described in the following list:

      +
    3. Let glyphs be the result of the + text preparation algorithm when measureText() was called.

    4. -
      -
      x attribute
      +
    5. Filter glyphs to include only the glyphs that correspond to code points within the range that includes the start + index but stops before the end index.

    6. -
      +
    7. +

      Split the given range of the text into clusters. Each cluster represents a minimal group + of characters such that their corresponding glyphs cannot be broken down any further, and each + character in the range is part of only one cluster. If a cluster is only partially contained by + the given character range, it should still be included.

      + +

      Return these clusters as a list of new TextCluster objects. These objects are + opaque as they encapsulate the complete text that was segmented, along with the + CanvasTextDrawingStyles values that were active at the time measureText() was called. Note that textAlign and textBaseline are exceptions, as they are + explicitly set attributes and are handled separately. Each TextCluster object has + members behaving as described in the following list:

      + +
      +
      x attribute
      + +

      The x coordinate of the cluster, on a coordinate space using CSS pixels, with its origin at the anchor point defined by the textAlign attribute (at the time left of each cluster). The selection criteria for this alignment point is explained in the section for this attribute of the cluster.

      -
      +
    8. -
      y attribute
      +
      y attribute
      -
      +

      The y coordinate of the cluster, on a coordinate space using CSS pixels, with its origin at the anchor point defined by the textBaseline attribute (at the time top of each cluster). The selection criteria for this alignment point is explained in the section for this attribute of the cluster.

      -
      +
    -
    start attribute
    +
    start attribute
    -

    The starting index for the range of code points that are - rendered as this cluster.

    +

    The starting index for the range of code points that are + rendered as this cluster.

    -
    end attribute
    +
    end attribute
    -

    The index immediately after the last included index for the range of code points that are rendered as this cluster.

    +

    The index immediately after the last included index for the range of code points that are rendered as this cluster.

    -
    align attribute
    +
    align attribute
    -

    The align for the specific point returned for the cluster. Let it be - options["align"] if it exists; otherwise, the textAlign attribute. Note that this doesn't change - the origin of the coordinate system, just which point is specified for each cluster.

    +

    The align for the specific point returned for the cluster. Let it be + options["align"] if it exists; otherwise, the textAlign attribute. Note that this doesn't change + the origin of the coordinate system, just which point is specified for each cluster.

    -
    baseline attribute
    +
    baseline attribute
    -

    The baseline for the specific point returned for the cluster. Let it be - options["baseline"] if it - exists; otherwise, the textBaseline attribute. Note that this doesn't - change the origin of the coordinate system, just which point is specified for each cluster. -

    - +

    The baseline for the specific point returned for the cluster. Let it be + options["baseline"] if it + exists; otherwise, the textBaseline attribute. Note that this doesn't + change the origin of the coordinate system, just which point is specified for each cluster. +

    + + + From affb8d7035049e2b748e79ea387fe80bb7ff846b Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 17 Mar 2025 11:27:58 -0400 Subject: [PATCH 16/18] Modern phrasing for getIndexFromOffset() --- source | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source b/source index 65f6026361f..30487a868fe 100644 --- a/source +++ b/source @@ -69524,13 +69524,24 @@ try { with accents that go beyond the flow of text will have a different paint bounding box.

    -
    getIndexFromOffset(offset) method
    +
    The getIndexFromOffset(offset) method steps are:
    -

    Returns the string index for the character at the given offset distance from the start - position of the text run, relative to the alignment point given by the textAlign attribute, with offset always increasing left - to right (negative offsets are valid). Values to the left or right of the text bounds will return - 0 or the length of the text, depending on the writing direction.

    +
    +
      +
    1. Let glyphs be the result of the + text preparation algorithm when measureText() was called.

    2. + +
    3. Let index be the character offset with the x position closest to + offset in glyphs.

    4. + +
    5. Return index.

    6. + +

      Note that negative values for offset are valid. Values to the left + or right of the text bounds will return 0 or the length of the text, depending on the writing + direction.

      +
    +
    The getTextClusters(start, end, options) method steps are:
    From b06cd1a11d736d5b462706342845922cdd39cdfc Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 17 Mar 2025 11:41:01 -0400 Subject: [PATCH 17/18] Add getTextCluster() version without (start, end) and add default for options --- source | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/source b/source index 30487a868fe..15d01cfb66a 100644 --- a/source +++ b/source @@ -65619,7 +65619,8 @@ interface TextMetrics { sequence<DOMRectReadOnly> getSelectionRects(unsigned long start, unsigned long end); DOMRectReadOnly getActualBoundingBox(unsigned long start, unsigned long end); unsigned long getIndexFromOffset(double offset); - sequence<TextCluster> getTextClusters(unsigned long start, unsigned long end, optional TextClusterOptions options); + sequence<TextCluster> getTextClusters(optional TextClusterOptions options = {}); + sequence<TextCluster> getTextClusters(unsigned long start, unsigned long end, optional TextClusterOptions options = {}); }; [Exposed=(Window,Worker)] @@ -69195,9 +69196,10 @@ try {

    Returns the index for the character at the given offset from the start of the text.

    +
    metrics.getTextClusters([ options ])
    metrics.getTextClusters(start, end [, options ])
    -

    Returns a list of TextCluster objects, with positional data for each one. +

    Return a list of TextCluster objects, with positional data for each one. They correspond to splitting the text into the minimal rendering units possible. The options dictionary enables selecting a specific point to be returned for each cluster be specifying align and baseline values.

    @@ -69543,6 +69545,19 @@ try { +
    The getTextClusters(options) method steps are:
    + +
    +
      +
    1. Let start be 0.

    2. + +
    3. Let end be the number of code points in the + measured text.

    4. + +
    5. Return getTextClusters(start, end, options).

    6. +
    +
    +
    The getTextClusters(start, end, options) method steps are:
    From 0aa3383fcb16e1174cedc79d0f59774ac3a1af62 Mon Sep 17 00:00:00 2001 From: Andres Ricardo Perez Date: Mon, 17 Mar 2025 11:57:10 -0400 Subject: [PATCH 18/18] Fix build issue with note for getIndexFromOffset() --- source | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source b/source index 15d01cfb66a..6df562c7808 100644 --- a/source +++ b/source @@ -69538,11 +69538,11 @@ try { offset in glyphs.

  • Return index.

  • - -

    Note that negative values for offset are valid. Values to the left - or right of the text bounds will return 0 or the length of the text, depending on the writing - direction.

    + +

    Negative values for offset are valid. Values to the left + or right of the text bounds will return 0 or the length of the text, depending on the writing + direction.

    The getTextClusters(options) method steps are: