Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: effd80c0d048afbb4cf0bb9a67eefa50f392d474
      
https://github.com/WebKit/WebKit/commit/effd80c0d048afbb4cf0bb9a67eefa50f392d474
  Author: Ahmad Saleem <[email protected]>
  Date:   2026-08-21 (Fri, 21 Aug 2026)

  Changed paths:
    M 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/element/text/2d.text.measure.width.space.html
    M 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space.html
    M 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space.worker.js
    M 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/tools/yaml-new/text.yaml
    M Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp

  Log Message:
  -----------
  [Canvas] CanvasRenderingContext2DBase::normalizeSpaces() widens Latin-1 text 
to UTF-16 and copies it twice
https://bugs.webkit.org/show_bug.cgi?id=322174
rdar://185404560

Reviewed by Gerald Squelart.

normalizeSpaces() replaces U+0009 through U+000D with U+0020 for every
fillText(), strokeText() and measureText() call. It unconditionally built a
Vector<char16_t>, so Latin-1 input came back 16-bit even though every replaced
character, and the replacement, is ASCII. That cost two fast paths on every draw
call: FontCascade::codePath() returns CodePath::Simple immediately for an 8-bit
run rather than scanning every character, and
TextUtil::containsStrongDirectionalityText(), which gates
canUseCachedShapedText(), skips its SIMD bidi scan for 8-bit text.

The Vector was copied twice as well: String::adopt(Vector&&) only adopts the
buffer when the vector's Malloc is StringImplMalloc, and Vector's default is
VectorBufferMalloc, so it fell through to create(vector.span()).

Dispatch on is8Bit() and build the result with String::createUninitialized(),
following StringImpl::createByReplacingInCharacters(): memcpy the prefix before
the first character needing replacement, then copy the remainder with the
replacement applied. 8-bit input stays 8-bit, in one allocation and one copy.

Also collapse isSpaceThatNeedsReplacing() to a range check, since U+0009 through
U+000D are contiguous. The same characters are matched; the range check is just
simpler to read, and clang already compiles both forms to the same code.

No change in behavior. Covered by existing tests, including
html/canvas/element/text/2d.text.draw.space.collapse.space.html, which is the
reason U+000B is matched despite not being a space character in the
specification.

Added cases to 2d.text.measure.width.space for strings whose only character
needing replacement is the last one, so the index returned by find() is the
final index and the prefix memcpy covers everything before it, down to a lone
U+0009 where the index is 0 and the prefix is empty. One case measures a
non-Latin-1 string both ways to cover the 16-bit path.
2d.text.measure.actualBoundingBox.whitespace.html already reaches that boundary
through measureText('A' + whitespace), but nothing pinned the resulting width.

* 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/element/text/2d.text.measure.width.space.html:
* 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space.html:
* 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/offscreen/text/2d.text.measure.width.space.worker.js:
* 
LayoutTests/imported/w3c/web-platform-tests/html/canvas/tools/yaml-new/text.yaml:
* Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp:
(WebCore::isSpaceThatNeedsReplacing):
(WebCore::createStringByNormalizingSpaces):
(WebCore::CanvasRenderingContext2DBase::normalizeSpaces):

Canonical link: https://commits.webkit.org/319591@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to