[cairo-commit] 2 commits - src/win32

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Feb 16 10:14:09 UTC 2023


 src/win32/cairo-dwrite-font.cpp |  130 +++++++++-------------------------------
 1 file changed, 31 insertions(+), 99 deletions(-)

New commits:
commit b7d8da7d1fb36f5257feba643d0d28e99a25ab09
Merge: 44d83d206 cce89abbb
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu Feb 16 10:14:07 2023 +0000

    Merge branch 'issue-641-glyph-bounds' into 'master'
    
    DWrite: clipped glyphs in win32 compositor
    
    Closes #641
    
    See merge request cairo/cairo!459

commit cce89abbb956c1fb1eabec84253e4d1f384870e8
Author: Fujii Hironori <Hironori.Fujii at sony.com>
Date:   Tue Feb 14 05:29:02 2023 +0900

    DWrite: clipped glyphs in win32 compositor
    
    The win32 compositor is using _cairo_dwrite_show_glyphs_on_surface for
    DWrite. It was assuming that a glyph was painted inside 3x3 of the em
    square. It should take the actual glyph bounding box by using
    GetAlphaTextureBounds.
    
    Fixes cairo/cairo#641

diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index edd606abe..4e6077188 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -1545,8 +1545,15 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
      */
     rt->SetPixelsPerDip(1.0);
 
+    float x = 0, y = 0;
     if (transform) {
-	rt->SetCurrentTransform(transform);
+	DWRITE_MATRIX matrix = *transform;
+	matrix.dx -= area.left;
+	matrix.dy -= area.top;
+	rt->SetCurrentTransform(&matrix);
+    } else {
+	x = (float) -area.left;
+	y = (float) -area.top;
     }
     BitBlt(rt->GetMemoryDC(),
 	   0, 0,
@@ -1554,7 +1561,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
 	   surface->dc,
 	   area.left, area.top,
 	   SRCCOPY | NOMIRRORBITMAP);
-    rt->DrawGlyphRun(0, 0, scaled_font->measuring_mode, run, params, color);
+    rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, params, color);
     BitBlt(surface->dc,
 	   area.left, area.top,
 	   area.right - area.left, area.bottom - area.top,
@@ -1590,6 +1597,7 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
     if (FAILED(hr))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    float x = 0, y = 0;
     if (transform) {
 	rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
 					  transform->m12,
@@ -1661,96 +1669,7 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
     DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
 
     BOOL transform = FALSE;
-    /* Needed to calculate bounding box for efficient blitting */
-    INT32 smallestX = INT_MAX;
-    INT32 largestX = 0;
-    INT32 smallestY = INT_MAX;
-    INT32 largestY = 0;
-    for (int i = 0; i < num_glyphs; i++) {
-	if (glyphs[i].x < smallestX) {
-	    smallestX = (INT32)glyphs[i].x;
-	}
-	if (glyphs[i].x > largestX) {
-	    largestX = (INT32)glyphs[i].x;
-	}
-	if (glyphs[i].y < smallestY) {
-	    smallestY = (INT32)glyphs[i].y;
-	}
-	if (glyphs[i].y > largestY) {
-	    largestY = (INT32)glyphs[i].y;
-	}
-    }
-    /*
-     * Here we try to get a rough estimate of the area that this glyph run will
-     * cover on the surface. Since we use GDI interop to draw we will be copying
-     * data around the size of the area of the surface that we map. We will want
-     * to map an area as small as possible to prevent large surfaces to be
-     * copied around. We take the X/Y-size of the font as margin on the left/top
-     * twice the X/Y-size of the font as margin on the right/bottom.
-     * This should always cover the entire area where the glyphs are.
-     */
-    RECT fontArea;
-    fontArea.left = (INT32)(smallestX - scaled_font->font_matrix.xx);
-    fontArea.right = (INT32)(largestX + scaled_font->font_matrix.xx * 2);
-    fontArea.top = (INT32)(smallestY - scaled_font->font_matrix.yy);
-    fontArea.bottom = (INT32)(largestY + scaled_font->font_matrix.yy * 2);
-    if (fontArea.left < 0)
-	fontArea.left = 0;
-    if (fontArea.top < 0)
-	fontArea.top = 0;
-    if (fontArea.bottom > dst->extents.height) {
-	fontArea.bottom = dst->extents.height;
-    }
-    if (fontArea.right > dst->extents.width) {
-	fontArea.right = dst->extents.width;
-    }
-    if (fontArea.right <= fontArea.left ||
-	fontArea.bottom <= fontArea.top) {
-	return CAIRO_INT_STATUS_SUCCESS;
-    }
-    if (fontArea.right > dst->extents.width) {
-	fontArea.right = dst->extents.width;
-    }
-    if (fontArea.bottom > dst->extents.height) {
-	fontArea.bottom = dst->extents.height;
-    }
-
-    run.bidiLevel = 0;
-    run.fontFace = dwriteff->dwriteface;
-    run.isSideways = FALSE;
-    if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
-	dwritesf->mat.xx == scaled_font->font_matrix.xx &&
-	dwritesf->mat.yy == scaled_font->font_matrix.yy) {
-
-	for (int i = 0; i < num_glyphs; i++) {
-	    indices[i] = (WORD) glyphs[i].index;
-	    // Since we will multiply by our ctm matrix later for rotation effects
-	    // and such, adjust positions by the inverse matrix now.
-	    offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y);
-	    offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
-	    advances[i] = 0.0;
-	}
-	run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
-    } else {
-	transform = TRUE;
-        // See comment about EPSILON in _cairo_dwrite_glyph_run_from_glyphs
-        const double EPSILON = 0.0001;
-	for (int i = 0; i < num_glyphs; i++) {
-	    indices[i] = (WORD) glyphs[i].index;
-	    double x = glyphs[i].x - fontArea.left + EPSILON;
-	    double y = glyphs[i].y - fontArea.top;
-	    cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
-	    /*
-	     * Since we will multiply by our ctm matrix later for rotation effects
-	     * and such, adjust positions by the inverse matrix now. The Y-axis
-	     * is inverted so the offset becomes negative.
-	     */
-	    offsets[i].ascenderOffset = -(FLOAT)y;
-	    offsets[i].advanceOffset = (FLOAT)x;
-	    advances[i] = 0.0;
-	}
-	run.fontEmSize = 1.0f;
-    }
+    _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
 
     cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
     COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8,
@@ -1766,18 +1685,31 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
 	mat = NULL;
     }
 
-    RECT area;
-    area.left = dst->extents.x;
-    area.top = dst->extents.y;
-    area.right = area.left + dst->extents.width;
-    area.bottom = area.top + dst->extents.height;
+    RefPtr<IDWriteGlyphRunAnalysis> runAnalysis;
+    HRESULT hr = DWriteFactory::Instance()->
+	CreateGlyphRunAnalysis(&run, 1, mat,
+			       DWRITE_RENDERING_MODE_ALIASED,
+			       dwritesf->measuring_mode,
+			       0, // baselineOriginX,
+			       0, // baselineOriginY,
+			       &runAnalysis);
+    if (FAILED(hr))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    RECT fontArea;
+    hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea);
+    if (FAILED(hr))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    InflateRect(&fontArea, 1, 1);
+    /* Needed to calculate bounding box for efficient blitting */
+    RECT copyArea, dstArea = { 0, 0, dst->extents.width, dst->extents.height };
+    IntersectRect(&copyArea, &fontArea, &dstArea);
 
 #ifdef CAIRO_TRY_D2D_TO_GDI
     status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
 						    mat,
 						    &run,
 						    color,
-						    fontArea);
+						    copyArea);
 
     if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) {
 #endif
@@ -1786,7 +1718,7 @@ _cairo_dwrite_show_glyphs_on_surface(void			*surface,
 							&run,
 							color,
 							dwritesf,
-							fontArea);
+							copyArea);
 
 #ifdef CAIRO_TRY_D2D_TO_GDI
     }


More information about the cairo-commit mailing list