[PATCH 3/4] dwrite: Implement GetAlphaTextureBounds()

Nikolay Sivov nsivov at codeweavers.com
Wed Jul 29 03:59:02 CDT 2015


---

-------------- next part --------------
>From 5a0737c7bcfabda32b9986525b6799aa9bb4dcec Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Wed, 29 Jul 2015 11:54:32 +0300
Subject: [PATCH 3/4] dwrite: Implement GetAlphaTextureBounds()

---
 dlls/dwrite/dwrite_private.h |  3 ++-
 dlls/dwrite/font.c           | 62 +++++++++++++++++++++++++++++++++++++++++---
 dlls/dwrite/freetype.c       | 35 +++++++++++++++++++++++--
 dlls/dwrite/main.c           |  4 +--
 dlls/dwrite/tests/font.c     | 12 +++------
 5 files changed, 98 insertions(+), 18 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index aa24550..0c25483 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -124,7 +124,7 @@ extern HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *refer
 extern HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) DECLSPEC_HIDDEN;
 extern HRESULT create_fontface(DWRITE_FONT_FACE_TYPE,UINT32,IDWriteFontFile* const*,UINT32,DWRITE_FONT_SIMULATIONS,IDWriteFontFace2**) DECLSPEC_HIDDEN;
 extern HRESULT create_font_collection(IDWriteFactory2*,IDWriteFontFileEnumerator*,BOOL,IDWriteFontCollection**) DECLSPEC_HIDDEN;
-extern HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE,DWRITE_GLYPH_RUN const*,IDWriteGlyphRunAnalysis**) DECLSPEC_HIDDEN;
+extern HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE,DWRITE_GLYPH_RUN const*,FLOAT,IDWriteGlyphRunAnalysis**) DECLSPEC_HIDDEN;
 extern BOOL    is_system_collection(IDWriteFontCollection*) DECLSPEC_HIDDEN;
 extern HRESULT get_local_refkey(const WCHAR*,const FILETIME*,void**,UINT32*) DECLSPEC_HIDDEN;
 extern HRESULT get_filestream_from_file(IDWriteFontFile*,IDWriteFontFileStream**) DECLSPEC_HIDDEN;
@@ -188,6 +188,7 @@ extern UINT16 freetype_get_glyphcount(IDWriteFontFace2*) DECLSPEC_HIDDEN;
 extern UINT16 freetype_get_glyphindex(IDWriteFontFace2*,UINT32) DECLSPEC_HIDDEN;
 extern BOOL freetype_has_kerning_pairs(IDWriteFontFace2*) DECLSPEC_HIDDEN;
 extern INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace2*,UINT16,UINT16) DECLSPEC_HIDDEN;
+extern void freetype_get_glyph_bbox(IDWriteFontFace2*,FLOAT,UINT16,BOOL,RECT*) DECLSPEC_HIDDEN;
 
 /* Glyph shaping */
 enum SCRIPT_JUSTIFY
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 3f016d6..60efcf3 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -106,15 +106,22 @@ struct dwrite_fonttable {
     BOOL   exists;
 };
 
+enum runanalysis_readystate {
+    RUNANALYSIS_BOUNDS  = 1 << 0,
+};
+
 struct dwrite_glyphrunanalysis {
     IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
     LONG ref;
 
     DWRITE_RENDERING_MODE rendering_mode;
     DWRITE_GLYPH_RUN run;
+    FLOAT ppdip;
     UINT16 *glyphs;
     FLOAT *advances;
     DWRITE_GLYPH_OFFSET *offsets;
+    RECT bounds;
+    UINT8 ready;
 };
 
 #define GLYPH_BLOCK_SHIFT 8
@@ -2904,11 +2911,16 @@ static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
     return ref;
 }
 
-static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT* bounds)
+static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
 {
     struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
+    IDWriteFontFace2 *fontface2;
+    BOOL nohint, is_rtl;
+    FLOAT origin_x;
+    HRESULT hr;
+    UINT32 i;
 
-    FIXME("(%p)->(%d %p): stub\n", This, type, bounds);
+    TRACE("(%p)->(%d %p)\n", This, type, bounds);
 
     if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
         memset(bounds, 0, sizeof(*bounds));
@@ -2921,7 +2933,46 @@ static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnal
         return S_OK;
     }
 
-    return E_NOTIMPL;
+    if (This->ready & RUNANALYSIS_BOUNDS) {
+        *bounds = This->bounds;
+        return S_OK;
+    }
+
+    if (This->run.isSideways)
+        FIXME("sideways runs are not supported.\n");
+
+    hr = IDWriteFontFace_QueryInterface(This->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
+    if (FAILED(hr))
+        WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
+
+    nohint = This->rendering_mode == DWRITE_RENDERING_MODE_NATURAL || This->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+
+    /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
+       RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
+       for any non-zero glyph ascender */
+    origin_x = 0.0;
+    is_rtl = This->run.bidiLevel & 1;
+    for (i = 0; i < This->run.glyphCount; i++) {
+        const DWRITE_GLYPH_OFFSET *offset = &This->offsets[i];
+        FLOAT advance = This->advances[i];
+        RECT bbox;
+
+        freetype_get_glyph_bbox(fontface2, This->run.fontEmSize * This->ppdip, This->run.glyphIndices[i], nohint, &bbox);
+
+        if (is_rtl)
+            OffsetRect(&bbox, origin_x - offset->advanceOffset - advance, -offset->ascenderOffset);
+        else
+            OffsetRect(&bbox, origin_x + offset->advanceOffset, offset->ascenderOffset);
+
+        UnionRect(&This->bounds, &This->bounds, &bbox);
+        origin_x += is_rtl ? -advance : advance;
+    }
+
+    IDWriteFontFace2_Release(fontface2);
+
+    This->ready |= RUNANALYSIS_BOUNDS;
+    *bounds = This->bounds;
+    return S_OK;
 }
 
 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
@@ -2977,7 +3028,7 @@ static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
     glyphrunanalysis_GetAlphaBlendParams
 };
 
-HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLYPH_RUN const *run, IDWriteGlyphRunAnalysis **ret)
+HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLYPH_RUN const *run, FLOAT ppdip, IDWriteGlyphRunAnalysis **ret)
 {
     struct dwrite_glyphrunanalysis *analysis;
 
@@ -2994,6 +3045,9 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLY
     analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
     analysis->ref = 1;
     analysis->rendering_mode = rendering_mode;
+    analysis->ready = 0;
+    analysis->ppdip = ppdip;
+    SetRectEmpty(&analysis->bounds);
     analysis->run = *run;
     IDWriteFontFace_AddRef(analysis->run.fontFace);
     analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 778f9cf..ff5172e 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -1,7 +1,7 @@
 /*
  *    FreeType integration
  *
- * Copyright 2014 Nikolay Sivov for CodeWeavers
+ * Copyright 2014-2015 Nikolay Sivov for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -54,6 +54,7 @@ static void *ft_handle = NULL;
 static FT_Library library = 0;
 static FTC_Manager cache_manager = 0;
 static FTC_CMapCache cmap_cache = 0;
+static FTC_ImageCache image_cache = 0;
 typedef struct
 {
     FT_Int major;
@@ -64,6 +65,7 @@ typedef struct
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
 MAKE_FUNCPTR(FT_Done_FreeType);
 MAKE_FUNCPTR(FT_Get_Kerning);
+MAKE_FUNCPTR(FT_Glyph_Get_CBox);
 MAKE_FUNCPTR(FT_Init_FreeType);
 MAKE_FUNCPTR(FT_Library_Version);
 MAKE_FUNCPTR(FT_Load_Glyph);
@@ -71,6 +73,8 @@ MAKE_FUNCPTR(FT_New_Memory_Face);
 MAKE_FUNCPTR(FT_Outline_Transform);
 MAKE_FUNCPTR(FTC_CMapCache_Lookup);
 MAKE_FUNCPTR(FTC_CMapCache_New);
+MAKE_FUNCPTR(FTC_ImageCache_Lookup);
+MAKE_FUNCPTR(FTC_ImageCache_New);
 MAKE_FUNCPTR(FTC_Manager_New);
 MAKE_FUNCPTR(FTC_Manager_Done);
 MAKE_FUNCPTR(FTC_Manager_LookupFace);
@@ -137,6 +141,7 @@ BOOL init_freetype(void)
 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(ft_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
     LOAD_FUNCPTR(FT_Done_FreeType)
     LOAD_FUNCPTR(FT_Get_Kerning)
+    LOAD_FUNCPTR(FT_Glyph_Get_CBox)
     LOAD_FUNCPTR(FT_Init_FreeType)
     LOAD_FUNCPTR(FT_Library_Version)
     LOAD_FUNCPTR(FT_Load_Glyph)
@@ -144,6 +149,8 @@ BOOL init_freetype(void)
     LOAD_FUNCPTR(FT_Outline_Transform)
     LOAD_FUNCPTR(FTC_CMapCache_Lookup)
     LOAD_FUNCPTR(FTC_CMapCache_New)
+    LOAD_FUNCPTR(FTC_ImageCache_Lookup)
+    LOAD_FUNCPTR(FTC_ImageCache_New)
     LOAD_FUNCPTR(FTC_Manager_New)
     LOAD_FUNCPTR(FTC_Manager_Done)
     LOAD_FUNCPTR(FTC_Manager_LookupFace)
@@ -161,7 +168,8 @@ BOOL init_freetype(void)
 
     /* init cache manager */
     if (pFTC_Manager_New(library, 0, 0, 0, &face_requester, NULL, &cache_manager) != 0 ||
-        pFTC_CMapCache_New(cache_manager, &cmap_cache) != 0) {
+        pFTC_CMapCache_New(cache_manager, &cmap_cache) != 0 ||
+        pFTC_ImageCache_New(cache_manager, &image_cache) != 0) {
 
         ERR("Failed to init FreeType cache\n");
         pFTC_Manager_Done(cache_manager);
@@ -456,6 +464,29 @@ INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace2 *fontface, UINT16 le
     return adjustment;
 }
 
+void freetype_get_glyph_bbox(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 index, BOOL nohint, RECT *ret)
+{
+    FTC_ImageTypeRec imagetype;
+    FT_BBox bbox = { 0 };
+    FT_Glyph glyph;
+
+    imagetype.face_id = fontface;
+    imagetype.width = 0;
+    imagetype.height = emSize;
+    imagetype.flags = nohint ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
+
+    EnterCriticalSection(&freetype_cs);
+    if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0)
+        pFT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &bbox);
+    LeaveCriticalSection(&freetype_cs);
+
+    /* flip Y axis */
+    ret->left = bbox.xMin;
+    ret->right = bbox.xMax;
+    ret->top = -bbox.yMax;
+    ret->bottom = -bbox.yMin;
+}
+
 #else /* HAVE_FREETYPE */
 
 BOOL init_freetype(void)
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index 7c027f9..9f8454f 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -1076,10 +1076,10 @@ static HRESULT WINAPI dwritefactory_CreateGlyphRunAnalysis(IDWriteFactory2 *ifac
 {
     struct dwritefactory *This = impl_from_IDWriteFactory2(iface);
 
-    TRACE("(%p)->(%p %f %p %d %d %f %f %p)\n", This, run, ppdip, transform, rendering_mode,
+    TRACE("(%p)->(%p %.2f %p %d %d %f %f %p)\n", This, run, ppdip, transform, rendering_mode,
         measuring_mode, baseline_x, baseline_y, analysis);
 
-    return create_glyphrunanalysis(rendering_mode, run, analysis);
+    return create_glyphrunanalysis(rendering_mode, run, ppdip, analysis);
 }
 
 static HRESULT WINAPI dwritefactory1_GetEudcFontCollection(IDWriteFactory2 *iface, IDWriteFontCollection **collection,
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 502930f..08de0d9 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -3500,10 +3500,9 @@ static void test_CreateGlyphRunAnalysis(void)
         if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
             memset(&rect, 0, sizeof(rect));
             hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
-        todo_wine {
             ok(hr == S_OK, "got 0x%08x\n", hr);
             ok(!IsRectEmpty(&rect), "got empty rect\n");
-        }
+
             rect.left = rect.top = 0;
             rect.bottom = rect.right = 1;
             hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
@@ -3519,11 +3518,9 @@ static void test_CreateGlyphRunAnalysis(void)
 
             memset(&rect, 0, sizeof(rect));
             hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
-        todo_wine {
             ok(hr == S_OK, "got 0x%08x\n", hr);
             ok(!IsRectEmpty(&rect), "got empty rect\n");
         }
-        }
 
         IDWriteGlyphRunAnalysis_Release(analysis);
     }
@@ -3542,10 +3539,7 @@ static void test_CreateGlyphRunAnalysis(void)
 
         memset(&rect, 0, sizeof(rect));
         hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
-    todo_wine
         ok(hr == S_OK, "got 0x%08x\n", hr);
-        if (hr != S_OK)
-            break;
 
         hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
              DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
@@ -3557,8 +3551,8 @@ static void test_CreateGlyphRunAnalysis(void)
 
         rect.right -= rect.left;
         rect.bottom -= rect.top;
-        ok(abs(bboxX - rect.right) <= 1, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
-        ok(abs(bboxY - rect.bottom) <= 1, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
+        ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
+        ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
 
         IDWriteGlyphRunAnalysis_Release(analysis);
     }
-- 
2.1.4



More information about the wine-patches mailing list