[PATCH 2/3] dwrite: Implement CreateAlphaTexture()

Nikolay Sivov nsivov at codeweavers.com
Thu Jul 30 17:30:08 CDT 2015


---

-------------- next part --------------
From 50a0d4951df87963e9aaba0950a9bde63442239f Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Fri, 31 Jul 2015 01:20:25 +0300
Subject: [PATCH 2/3] dwrite: Implement CreateAlphaTexture()

---
 dlls/dwrite/dwrite_private.h |   1 +
 dlls/dwrite/font.c           | 130 ++++++++++++++++++++++++++++++++++++++++---
 dlls/dwrite/freetype.c       |  65 +++++++++++++++++++++-
 include/dwrite.idl           |   2 +
 4 files changed, 189 insertions(+), 9 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 59bef03..b0168ae 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -189,6 +189,7 @@ 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;
+extern void freetype_get_glyph_bitmap(IDWriteFontFace2*,FLOAT,UINT16,const RECT*,BYTE*) DECLSPEC_HIDDEN;
 
 /* Glyph shaping */
 enum SCRIPT_JUSTIFY
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 5f32c31..d72f8a6 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -1,6 +1,7 @@
 /*
  *    Font and collections
  *
+ * Copyright 2011 Huw Davies
  * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
  * Copyright 2014 Aric Stewart for CodeWeavers
  *
@@ -108,6 +109,7 @@ struct dwrite_fonttable {
 
 enum runanalysis_readystate {
     RUNANALYSIS_BOUNDS  = 1 << 0,
+    RUNANALYSIS_BITMAP  = 1 << 1,
 };
 
 struct dwrite_glyphrunanalysis {
@@ -122,8 +124,10 @@ struct dwrite_glyphrunanalysis {
     UINT16 *glyphs;
     FLOAT *advances;
     DWRITE_GLYPH_OFFSET *offsets;
-    RECT bounds;
+
     UINT8 ready;
+    RECT bounds;
+    BYTE *bitmap;
 };
 
 #define GLYPH_BLOCK_SHIFT 8
@@ -2907,6 +2911,7 @@ static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
         heap_free(This->glyphs);
         heap_free(This->advances);
         heap_free(This->offsets);
+        heap_free(This->bitmap);
         heap_free(This);
     }
 
@@ -2986,6 +2991,99 @@ static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnal
     return S_OK;
 }
 
+static inline int get_dib_stride( int width, int bpp )
+{
+    return ((width * bpp + 31) >> 3) & ~3;
+}
+
+static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
+{
+    if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
+        return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
+            (runbounds->left - bounds->left) * 3;
+    else
+        return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
+            runbounds->left - bounds->left;
+}
+
+static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
+{
+    static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+    IDWriteFontFace2 *fontface2;
+    BOOL is_rtl, nohint;
+    FLOAT origin_x;
+    UINT32 i, size;
+
+    IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
+
+    nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL || analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
+
+    size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
+    if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
+        size *= 3;
+    analysis->bitmap = heap_alloc_zero(size);
+
+    origin_x = 0.0;
+    is_rtl = analysis->run.bidiLevel & 1;
+    for (i = 0; i < analysis->run.glyphCount; i++) {
+        const DWRITE_GLYPH_OFFSET *offset = &analysis->offsets[i];
+        FLOAT advance = analysis->advances[i];
+        int pitch, x, y, width, height;
+        BYTE *glyph, *src, *dst;
+        RECT bbox;
+
+        freetype_get_glyph_bbox(fontface2, analysis->run.fontEmSize * analysis->ppdip, analysis->run.glyphIndices[i], nohint, &bbox);
+
+        if (IsRectEmpty(&bbox)) {
+            origin_x += is_rtl ? -advance : advance;
+            continue;
+        }
+
+        width = bbox.right - bbox.left;
+        height = bbox.bottom - bbox.top;
+        pitch = ((width + 31) >> 5) << 2;
+
+        src = glyph = heap_alloc_zero((bbox.bottom - bbox.top) * pitch);
+        freetype_get_glyph_bitmap(fontface2, analysis->run.fontEmSize * analysis->ppdip, analysis->run.glyphIndices[i], &bbox, glyph);
+
+        if (is_rtl)
+            OffsetRect(&bbox, origin_x - offset->advanceOffset - advance, -offset->ascenderOffset);
+        else
+            OffsetRect(&bbox, origin_x + offset->advanceOffset, offset->ascenderOffset);
+
+        OffsetRect(&bbox, analysis->originX, analysis->originY);
+
+        /* blit to analysis bitmap */
+        dst = get_pixel_ptr(analysis->bitmap, type, &bbox, &analysis->bounds);
+
+        /* convert 1bpp to 8bpp/24bpp */
+        if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
+            for (y = 0; y < height; y++) {
+                for (x = 0; x < width; x++)
+                    dst[3*x] = dst[3*x+1] = dst[3*x+2] = (src[x / 8] & masks[x % 8]) ? DWRITE_ALPHA_MAX : 0;
+                src += get_dib_stride(width, 1);
+                dst += (analysis->bounds.right - analysis->bounds.left) * 3;
+            }
+        }
+        else {
+            for (y = 0; y < height; y++) {
+                for (x = 0; x < width; x++)
+                    dst[x] = (src[x / 8] & masks[x % 8]) ? DWRITE_ALPHA_MAX : 0;
+                src += get_dib_stride(width, 1);
+                dst += analysis->bounds.right - analysis->bounds.left;
+            }
+        }
+
+        heap_free(glyph);
+
+        origin_x += is_rtl ? -advance : advance;
+    }
+
+    IDWriteFontFace2_Release(fontface2);
+
+    analysis->ready |= RUNANALYSIS_BITMAP;
+}
+
 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
     RECT const *bounds, BYTE *bitmap, UINT32 size)
 {
@@ -2993,7 +3091,7 @@ static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysi
     UINT32 required;
     RECT runbounds;
 
-    FIXME("(%p)->(%d %s %p %u): stub\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
+    TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
 
     if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
         return E_INVALIDARG;
@@ -3024,15 +3122,30 @@ static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysi
         ;
     }
 
+    memset(bitmap, 0, size);
     glyphrunanalysis_get_texturebounds(This, &runbounds);
-
-    /* special case when there's nothing to return */
-    if (!IntersectRect(&runbounds, &runbounds, bounds)) {
-        memset(bitmap, 0, size);
-        return S_OK;
+    if (IntersectRect(&runbounds, &runbounds, bounds)) {
+        int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
+        int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
+        int dst_width = (bounds->right - bounds->left) * pixel_size;
+        int draw_width = (runbounds.right - runbounds.left) * pixel_size;
+        BYTE *src, *dst;
+        int y;
+
+        if (!(This->ready & RUNANALYSIS_BITMAP))
+            glyphrunanalysis_render(This, type);
+
+        src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
+        dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
+
+        for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
+            memcpy(dst, src, draw_width);
+            src += src_width;
+            dst += dst_width;
+        }
     }
 
-    return E_NOTIMPL;
+    return S_OK;
 }
 
 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
@@ -3099,6 +3212,7 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLY
     analysis->ref = 1;
     analysis->rendering_mode = rendering_mode;
     analysis->ready = 0;
+    analysis->bitmap = NULL;
     analysis->ppdip = ppdip;
     analysis->originX = originX;
     analysis->originY = originY;
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 0e8b976..711d601 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -70,7 +70,9 @@ MAKE_FUNCPTR(FT_Init_FreeType);
 MAKE_FUNCPTR(FT_Library_Version);
 MAKE_FUNCPTR(FT_Load_Glyph);
 MAKE_FUNCPTR(FT_New_Memory_Face);
+MAKE_FUNCPTR(FT_Outline_Get_Bitmap);
 MAKE_FUNCPTR(FT_Outline_Transform);
+MAKE_FUNCPTR(FT_Outline_Translate);
 MAKE_FUNCPTR(FTC_CMapCache_Lookup);
 MAKE_FUNCPTR(FTC_CMapCache_New);
 MAKE_FUNCPTR(FTC_ImageCache_Lookup);
@@ -146,7 +148,9 @@ BOOL init_freetype(void)
     LOAD_FUNCPTR(FT_Library_Version)
     LOAD_FUNCPTR(FT_Load_Glyph)
     LOAD_FUNCPTR(FT_New_Memory_Face)
+    LOAD_FUNCPTR(FT_Outline_Get_Bitmap)
     LOAD_FUNCPTR(FT_Outline_Transform)
+    LOAD_FUNCPTR(FT_Outline_Translate)
     LOAD_FUNCPTR(FTC_CMapCache_Lookup)
     LOAD_FUNCPTR(FTC_CMapCache_New)
     LOAD_FUNCPTR(FTC_ImageCache_Lookup)
@@ -473,7 +477,7 @@ void freetype_get_glyph_bbox(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 in
     imagetype.face_id = fontface;
     imagetype.width = 0;
     imagetype.height = emSize;
-    imagetype.flags = nohint ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
+    imagetype.flags = FT_LOAD_DEFAULT;
 
     EnterCriticalSection(&freetype_cs);
     if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0)
@@ -487,6 +491,59 @@ void freetype_get_glyph_bbox(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 in
     ret->bottom = -bbox.yMin;
 }
 
+void freetype_get_glyph_bitmap(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 index, const RECT *bbox, BYTE *buf)
+{
+    FTC_ImageTypeRec imagetype;
+    FT_Glyph glyph;
+
+    imagetype.face_id = fontface;
+    imagetype.width = 0;
+    imagetype.height = emSize;
+    imagetype.flags = FT_LOAD_DEFAULT;
+
+    EnterCriticalSection(&freetype_cs);
+    if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0) {
+        int width = bbox->right - bbox->left;
+        int pitch = ((width + 31) >> 5) << 2;
+        int height = bbox->bottom - bbox->top;
+
+        if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+            FT_OutlineGlyph outline = (FT_OutlineGlyph)glyph;
+
+            FT_Bitmap ft_bitmap;
+
+            ft_bitmap.width = width;
+            ft_bitmap.rows = height;
+            ft_bitmap.pitch = pitch;
+            ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
+            ft_bitmap.buffer = buf;
+
+            pFT_Outline_Translate(&outline->outline, -bbox->left, -bbox->bottom);
+
+            /* Note: FreeType will only set 'black' bits for us. */
+            memset(buf, 0, height*pitch);
+            pFT_Outline_Get_Bitmap(library, &outline->outline, &ft_bitmap);
+        }
+        else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+            FT_Bitmap *bitmap = &((FT_BitmapGlyph)glyph)->bitmap;
+            BYTE *src = bitmap->buffer, *dst = buf;
+            int w = min(pitch, (bitmap->width + 7) >> 3);
+            int h = min(height, bitmap->rows);
+
+            memset(buf, 0, height*pitch);
+
+            while (h--) {
+                memcpy(dst, src, w);
+                src += bitmap->pitch;
+                dst += pitch;
+            }
+        }
+        else
+            FIXME("format %d not handled\n", glyph->format);
+    }
+    LeaveCriticalSection(&freetype_cs);
+}
+
 #else /* HAVE_FREETYPE */
 
 BOOL init_freetype(void)
@@ -543,4 +600,10 @@ void freetype_get_glyph_bbox(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 in
     ret->left = ret->right = ret->top = ret->bottom = 0;
 }
 
+void freetype_get_glyph_bitmap(IDWriteFontFace2 *fontface, FLOAT emSize, UINT16 index, const RECT *bbox, BYTE *buf)
+{
+    UINT32 size = (bbox->right - bbox->left)*(bbox->bottom - bbox->top);
+    memset(buf, 0, size);
+}
+
 #endif /* HAVE_FREETYPE */
diff --git a/include/dwrite.idl b/include/dwrite.idl
index 2ae5164..bb41b4f 100644
--- a/include/dwrite.idl
+++ b/include/dwrite.idl
@@ -328,6 +328,8 @@ typedef enum DWRITE_NUMBER_SUBSTITUTION_METHOD
     DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL
 } DWRITE_NUMBER_SUBSTITUTION_METHOD;
 
+cpp_quote("#define DWRITE_ALPHA_MAX 255")
+
 typedef enum DWRITE_TEXTURE_TYPE
 {
     DWRITE_TEXTURE_ALIASED_1x1,
-- 
2.1.4



More information about the wine-patches mailing list