Skip to content

Commit c84f606

Browse files
committed
fix(text): draw Fabric text with grayscale antialiasing on transparent surfaces
RenderText calls ID2D1RenderTarget::DrawTextLayout without setting a text antialias mode, inheriting the device context default - ClearType subpixel antialiasing. The target is transparent: ParagraphComponentView creates the drawing surface DirectXAlphaMode::Premultiplied and clears it to ColorF(Black, 0.0f) when the view has no backgroundColor. ClearType needs an opaque, known background to filter against; with none, its per-channel coverage lands in the surface colour channels and shows as dark or colour-tinted fringes along thin glyph stems once composited. D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE is the documented mode for transparent render targets. Saves, sets GRAYSCALE, and restores - mirroring the GetAntialiasMode/ SetAntialiasMode and GetDpi/SetDpi save/restore idioms already in this function. 0.83-stable twin of #16341. Addresses #16340. Verified this branch has the same omission at the same line: SetTextAntialiasMode and D2D1_TEXT_ANTIALIAS_MODE have zero occurrences here too.
1 parent 8e869d7 commit c84f606

2 files changed

Lines changed: 13 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"packageName":"react-native-windows","comment":"Fix(text): draw Fabric text with grayscale antialiasing on transparent composition surfaces, preventing ClearType colour fringing on thin glyph stems","type":"patch","dependentChangeType":"patch","email":"collindanielschneide@gmail.com"}

vnext/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,24 @@ void RenderText(
165165
position += length;
166166
}
167167

168+
// The composition drawing surface this text lands on is premultiplied-alpha and is transparent
169+
// wherever the view has no opaque background; the surface is then composited by the visual tree,
170+
// possibly under an opacity or a transform. ClearType subpixel antialiasing has no valid opaque
171+
// background to filter against in that situation, and its per-channel coverage survives into the
172+
// surface's color channels as dark/colored fringes along thin glyph stems. Grayscale antialiasing
173+
// is the correct mode for transparent render targets, so ask for it explicitly rather than
174+
// inheriting whatever the device context defaults to.
175+
auto oldTextAntialiasMode = deviceContext.GetTextAntialiasMode();
176+
deviceContext.SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
177+
168178
// Draw the line of text at the specified offset, which corresponds to the top-left
169179
// corner of our drawing surface. Notice we don't call BeginDraw on the D2D device
170180
// context; this has already been done for us by the composition API.
171181
deviceContext.DrawTextLayout(
172182
D2D1::Point2F(offsetX, offsetY), &textLayout, brush.get(), D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
173183

184+
deviceContext.SetTextAntialiasMode(oldTextAntialiasMode);
185+
174186
// restore dpi to old state
175187
deviceContext.SetDpi(oldDpiX, oldDpiY);
176188
}

0 commit comments

Comments
 (0)