[PATCH] dwrite: Implement GetOverhangMetrics()

Nikolay Sivov nsivov at codeweavers.com
Thu Jan 26 15:42:13 CST 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |   1 +
 dlls/dwrite/freetype.c       |  31 ++++++++++
 dlls/dwrite/layout.c         | 135 +++++++++++++++++++++++++++++++++++++++----
 3 files changed, 155 insertions(+), 12 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 882567c7a0..d91735d994 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -287,6 +287,7 @@ extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
 extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
 extern INT freetype_get_charmap_index(IDWriteFontFace4*,BOOL*) DECLSPEC_HIDDEN;
 extern INT32 freetype_get_glyph_advance(IDWriteFontFace4*,FLOAT,UINT16,DWRITE_MEASURING_MODE) DECLSPEC_HIDDEN;
+extern void freetype_get_design_glyph_bbox(IDWriteFontFace4*,UINT16,UINT16,RECT*) DECLSPEC_HIDDEN;
 
 /* Glyph shaping */
 enum SCRIPT_JUSTIFY
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 9cc157e122..31a511b7b9 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -639,6 +639,32 @@ void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
     SetRect(&bitmap->bbox, bbox.xMin, -bbox.yMax, bbox.xMax, -bbox.yMin);
 }
 
+void freetype_get_design_glyph_bbox(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, RECT *bbox)
+{
+    FTC_ScalerRec scaler;
+    FT_Size size;
+
+    scaler.face_id = fontface;
+    scaler.width  = unitsperEm;
+    scaler.height = unitsperEm;
+    scaler.pixel = 1;
+    scaler.x_res = 0;
+    scaler.y_res = 0;
+
+    EnterCriticalSection(&freetype_cs);
+    if (pFTC_Manager_LookupSize(cache_manager, &scaler, &size) == 0) {
+         if (pFT_Load_Glyph(size->face, glyph, FT_LOAD_NO_SCALE) == 0) {
+             FT_Glyph_Metrics *metrics = &size->face->glyph->metrics;
+
+             bbox->left = metrics->horiBearingX;
+             bbox->right = bbox->left + metrics->horiAdvance;
+             bbox->top = -metrics->horiBearingY;
+             bbox->bottom = bbox->top + metrics->height;
+         }
+    }
+    LeaveCriticalSection(&freetype_cs);
+}
+
 static BOOL freetype_get_aliased_glyph_bitmap(struct dwrite_glyphbitmap *bitmap, FT_Glyph glyph)
 {
     const RECT *bbox = &bitmap->bbox;
@@ -889,6 +915,11 @@ void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap)
     memset(&bitmap->bbox, 0, sizeof(bitmap->bbox));
 }
 
+void freetype_get_design_glyph_bbox(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, D2D_RECT_F *bbox)
+{
+    memset(bbox, 0, sizeof(*bbox));
+}
+
 BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap)
 {
     return FALSE;
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 0d1ffb4c13..014fba420c 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -223,10 +223,12 @@ struct layout_cluster {
 };
 
 enum layout_recompute_mask {
-    RECOMPUTE_CLUSTERS      = 1 << 0,
-    RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
-    RECOMPUTE_LINES         = 1 << 2,
-    RECOMPUTE_EVERYTHING    = 0xffff
+    RECOMPUTE_CLUSTERS            = 1 << 0,
+    RECOMPUTE_MINIMAL_WIDTH       = 1 << 1,
+    RECOMPUTE_LINES               = 1 << 2,
+    RECOMPUTE_OVERHANGS           = 1 << 3,
+    RECOMPUTE_LINES_AND_OVERHANGS = RECOMPUTE_LINES | RECOMPUTE_OVERHANGS,
+    RECOMPUTE_EVERYTHING          = 0xffff
 };
 
 struct dwrite_textlayout {
@@ -267,6 +269,7 @@ struct dwrite_textlayout {
     UINT32 line_alloc;
 
     DWRITE_TEXT_METRICS1 metrics;
+    DWRITE_OVERHANG_METRICS overhangs;
 
     DWRITE_MEASURING_MODE measuringmode;
 
@@ -2905,7 +2908,7 @@ static HRESULT WINAPI dwritetextlayout_SetMaxWidth(IDWriteTextLayout3 *iface, FL
     This->metrics.layoutWidth = maxWidth;
 
     if (changed)
-        This->recompute |= RECOMPUTE_LINES;
+        This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
     return S_OK;
 }
 
@@ -2923,7 +2926,7 @@ static HRESULT WINAPI dwritetextlayout_SetMaxHeight(IDWriteTextLayout3 *iface, F
     This->metrics.layoutHeight = maxHeight;
 
     if (changed)
-        This->recompute |= RECOMPUTE_LINES;
+        This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
     return S_OK;
 }
 
@@ -3468,11 +3471,119 @@ static HRESULT WINAPI dwritetextlayout_GetMetrics(IDWriteTextLayout3 *iface, DWR
     return hr;
 }
 
-static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface, DWRITE_OVERHANG_METRICS *overhangs)
+static void scale_glyph_bbox(RECT *bbox, FLOAT emSize, UINT16 units_per_em, D2D_RECT_F *ret)
+{
+#define SCALE(x) ((FLOAT)x * emSize / (FLOAT)units_per_em)
+    ret->left = SCALE(bbox->left);
+    ret->right = SCALE(bbox->right);
+    ret->top = SCALE(bbox->top);
+    ret->bottom = SCALE(bbox->bottom);
+#undef SCALE
+}
+
+static void d2d_rect_offset(D2D_RECT_F *rect, FLOAT x, FLOAT y)
+{
+    rect->left += x;
+    rect->right += x;
+    rect->top += y;
+    rect->bottom += y;
+}
+
+static BOOL d2d_rect_is_empty(const D2D_RECT_F *rect)
+{
+    return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
+}
+
+static void d2d_rect_union(D2D_RECT_F *dst, const D2D_RECT_F *src)
+{
+    if (d2d_rect_is_empty(dst)) {
+        if (d2d_rect_is_empty(src)) {
+            dst->left = dst->right = dst->top = dst->bottom = 0.0f;
+            return;
+        }
+        else
+            *dst = *src;
+    }
+    else {
+        if (!d2d_rect_is_empty(src)) {
+            dst->left   = min(dst->left, src->left);
+            dst->right  = max(dst->right, src->right);
+            dst->top    = min(dst->top, src->top);
+            dst->bottom = max(dst->bottom, src->bottom);
+        }
+    }
+}
+
+static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout_effective_run *run, D2D_RECT_F *bbox)
+{
+    const struct regular_layout_run *regular = &run->run->u.regular;
+    UINT32 start_glyph = regular->clustermap[run->start];
+    const DWRITE_GLYPH_RUN *glyph_run = &regular->run;
+    DWRITE_FONT_METRICS font_metrics;
+    D2D_POINT_2F origin = { 0 };
+    UINT32 i;
+
+    IDWriteFontFace_GetMetrics(glyph_run->fontFace, &font_metrics);
+
+    origin.x = run->origin_x + run->align_dx;
+    origin.y = run->origin_y;
+    for (i = 0; i < run->glyphcount; i++) {
+        D2D_RECT_F glyph_bbox;
+        RECT design_bbox;
+
+        freetype_get_design_glyph_bbox((IDWriteFontFace4 *)glyph_run->fontFace, font_metrics.designUnitsPerEm,
+                glyph_run->glyphIndices[i + start_glyph], &design_bbox);
+
+        scale_glyph_bbox(&design_bbox, glyph_run->fontEmSize, font_metrics.designUnitsPerEm, &glyph_bbox);
+        d2d_rect_offset(&glyph_bbox, origin.x + glyph_run->glyphOffsets[i + start_glyph].advanceOffset,
+                origin.y + glyph_run->glyphOffsets[i + start_glyph].ascenderOffset);
+        d2d_rect_union(bbox, &glyph_bbox);
+
+        /* FIXME: take care of vertical/rtl */
+        origin.x += glyph_run->glyphAdvances[i + start_glyph];
+    }
+}
+
+static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface,
+        DWRITE_OVERHANG_METRICS *overhangs)
 {
     struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
-    FIXME("(%p)->(%p): stub\n", This, overhangs);
-    return E_NOTIMPL;
+    struct layout_effective_run *run;
+    D2D_RECT_F bbox = { 0 };
+    HRESULT hr;
+
+    TRACE("(%p)->(%p)\n", This, overhangs);
+
+    memset(overhangs, 0, sizeof(*overhangs));
+
+    if (!(This->recompute & RECOMPUTE_OVERHANGS)) {
+        *overhangs = This->overhangs;
+        return S_OK;
+    }
+
+    hr = layout_compute_effective_runs(This);
+    if (FAILED(hr))
+        return hr;
+
+    LIST_FOR_EACH_ENTRY(run, &This->eruns, struct layout_effective_run, entry) {
+        D2D_RECT_F run_bbox;
+
+        layout_get_erun_bbox(This, run, &run_bbox);
+        d2d_rect_union(&bbox, &run_bbox);
+    }
+
+    /* FIXME: iterate over inline objects too */
+
+    /* deltas from text content metrics */
+    This->overhangs.left = -bbox.left;
+    This->overhangs.top = -bbox.top;
+    This->overhangs.right = bbox.right - This->metrics.layoutWidth;
+    This->overhangs.bottom = bbox.bottom - This->metrics.layoutHeight;
+    This->recompute &= ~RECOMPUTE_OVERHANGS;
+
+    *overhangs = This->overhangs;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout3 *iface,
@@ -3739,7 +3850,7 @@ static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface
         return hr;
 
     if (changed)
-        This->recompute = RECOMPUTE_LINES;
+        This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
 
     return S_OK;
 }
@@ -3930,7 +4041,7 @@ static HRESULT WINAPI dwritetextformat_layout_SetWordWrapping(IDWriteTextFormat1
         return hr;
 
     if (changed)
-        This->recompute |= RECOMPUTE_LINES;
+        This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
 
     return S_OK;
 }
@@ -3990,7 +4101,7 @@ static HRESULT WINAPI dwritetextformat_layout_SetTrimming(IDWriteTextFormat1 *if
     hr = format_set_trimming(&This->format, trimming, trimming_sign, &changed);
 
     if (changed)
-        This->recompute |= RECOMPUTE_LINES;
+        This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS;
 
     return hr;
 }
-- 
2.11.0




More information about the wine-patches mailing list