2 #include "dw_renderer.h"
3 #include "helper_func.h"
6 IDWriteFactory
*dw_renderer::_dw_factory
= NULL
;
7 IDWriteGdiInterop
*dw_renderer::_dw_gdi_interop
= NULL
;
9 dw_renderer::dw_renderer()
13 if (_dw_factory
== NULL
)
15 hr
= DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED
, __uuidof(IDWriteFactory
), reinterpret_cast<IUnknown
**>(&_dw_factory
));
18 mem_man_instance
.register_com_ptr(_dw_factory
);
21 if (_dw_gdi_interop
== NULL
)
23 hr
= _dw_factory
->GetGdiInterop(&_dw_gdi_interop
);
26 mem_man_instance
.register_com_ptr(_dw_gdi_interop
);
30 bool dw_renderer::begin(const dc_context
*context
, FT_Render_Mode render_mode
)
32 if (!renderer::begin(context
, render_mode
))
36 if (_context
->log_font
.lfEscapement
% 3600 != 0)
39 switch (_context
->setting_cache
->hinting
)
42 _dw_measuring_mode
= DWRITE_MEASURING_MODE_GDI_NATURAL
;
45 _dw_measuring_mode
= DWRITE_MEASURING_MODE_GDI_CLASSIC
;
48 _dw_measuring_mode
= DWRITE_MEASURING_MODE_NATURAL
;
51 _use_gdi_natural
= (_dw_measuring_mode
!= DWRITE_MEASURING_MODE_GDI_CLASSIC
);
54 _em_size
= static_cast<FLOAT
>(_context
->outline_metrics
->otmTextMetrics
.tmHeight
- _context
->outline_metrics
->otmTextMetrics
.tmInternalLeading
);
55 _pixels_per_dip
= GetDeviceCaps(_context
->hdc
, LOGPIXELSY
) / 96.0f
;
60 //////////////////////////////////////////////////////////////////////////
62 bool dw_renderer::make_glyph_texture(FLOAT x
, FLOAT y
, const DWRITE_GLYPH_RUN
*dw_glyph_run
, glyph_run
*a_glyph_run
)
66 DWRITE_RENDERING_MODE dw_render_mode
;
67 if (_render_mode
== FT_RENDER_MODE_LCD
)
69 switch (_context
->setting_cache
->hinting
)
72 dw_render_mode
= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL
;
75 dw_render_mode
= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL
;
78 dw_render_mode
= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC
;
81 dw_render_mode
= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC
;
86 dw_render_mode
= DWRITE_RENDERING_MODE_ALIASED
;
88 DWRITE_TEXTURE_TYPE dw_texture_type
;
91 if (_render_mode
== FT_RENDER_MODE_MONO
)
93 else if (_render_mode
== FT_RENDER_MODE_LCD
)
95 dw_texture_type
= DWRITE_TEXTURE_CLEARTYPE_3x1
;
97 ft_pixel_mode
= FT_PIXEL_MODE_LCD
;
101 dw_texture_type
= DWRITE_TEXTURE_ALIASED_1x1
;
103 ft_pixel_mode
= FT_PIXEL_MODE_GRAY
;
106 CComPtr
<IDWriteGlyphRunAnalysis
> dw_analysis
;
107 hr
= _dw_factory
->CreateGlyphRunAnalysis(dw_glyph_run
,
118 hr
= dw_analysis
->GetAlphaTextureBounds(dw_texture_type
, &texture_rect
);
121 if (IsRectEmpty(&texture_rect
))
124 const LONG texture_width
= texture_rect
.right
- texture_rect
.left
;
125 const LONG texture_height
= texture_rect
.bottom
- texture_rect
.top
;
127 FT_BitmapGlyph new_bmp_glyph
= new FT_BitmapGlyphRec();
128 new_bmp_glyph
->left
= texture_rect
.left
;
129 new_bmp_glyph
->top
= -texture_rect
.top
;
130 new_bmp_glyph
->bitmap
.rows
= texture_rect
.bottom
- texture_rect
.top
;
131 new_bmp_glyph
->bitmap
.width
= texture_width
* bytes_per_pixel
;
132 new_bmp_glyph
->bitmap
.pitch
= new_bmp_glyph
->bitmap
.width
;
133 new_bmp_glyph
->bitmap
.pixel_mode
= ft_pixel_mode
;
135 const int bmp_size
= new_bmp_glyph
->bitmap
.pitch
* new_bmp_glyph
->bitmap
.rows
;
136 new_bmp_glyph
->bitmap
.buffer
= new BYTE
[bmp_size
];
137 hr
= dw_analysis
->CreateAlphaTexture(dw_texture_type
, &texture_rect
, new_bmp_glyph
->bitmap
.buffer
, bmp_size
);
140 RECT ctrl_box
, black_box
;
141 ctrl_box
.left
= static_cast<LONG
>(x
);
142 ctrl_box
.top
= static_cast<LONG
>(y
);
143 ctrl_box
.right
= texture_width
;
144 ctrl_box
.bottom
= ctrl_box
.top
;
145 black_box
.left
= ctrl_box
.left
+ texture_rect
.left
;
146 black_box
.top
= ctrl_box
.top
;
147 black_box
.right
= black_box
.left
+ texture_width
;
148 black_box
.bottom
= ctrl_box
.bottom
;
150 a_glyph_run
->glyphs
.push_back(reinterpret_cast<FT_Glyph
>(new_bmp_glyph
));
151 a_glyph_run
->ctrl_boxes
.push_back(ctrl_box
);
152 a_glyph_run
->black_boxes
.push_back(black_box
);
157 bool dw_renderer::render_glyph(LPCWSTR lpString
, UINT c
, glyph_run
&new_glyph_run
)
161 CComPtr
<IDWriteFontFace
> dw_font_face
;
162 hr
= _dw_gdi_interop
->CreateFontFaceFromHdc(_context
->hdc
, &dw_font_face
);
165 DWRITE_GLYPH_RUN dw_glyph_run
;
166 dw_glyph_run
.fontFace
= dw_font_face
;
167 dw_glyph_run
.fontEmSize
= _em_size
;
168 dw_glyph_run
.glyphCount
= c
;
169 dw_glyph_run
.glyphIndices
= reinterpret_cast<const UINT16
*>(lpString
);
170 dw_glyph_run
.glyphAdvances
= (_advances
.empty() ? NULL
: _advances
.data());
171 dw_glyph_run
.glyphOffsets
= NULL
;
172 dw_glyph_run
.isSideways
= FALSE
;
173 dw_glyph_run
.bidiLevel
= 0;
175 return make_glyph_texture(0, 0, &dw_glyph_run
, &new_glyph_run
);
178 bool dw_renderer::render_text(LPCWSTR lpString
, UINT c
, glyph_run
&new_glyph_run
)
182 const long font_id
= font_man_instance
.register_font(_context
->hdc
, metric_face_name(_context
->outline_metrics
));
184 const os2_metrics
*os2_metrics
= font_man_instance
.lookup_os2_metrics(font_id
);
186 DWRITE_FONT_STYLE dw_font_style
;
187 if (!_context
->outline_metrics
->otmTextMetrics
.tmItalic
)
188 dw_font_style
= DWRITE_FONT_STYLE_NORMAL
;
189 else if (os2_metrics
->is_italic())
190 dw_font_style
= DWRITE_FONT_STYLE_ITALIC
;
192 dw_font_style
= DWRITE_FONT_STYLE_OBLIQUE
;
194 CComPtr
<IDWriteTextFormat
> dw_text_format
;
195 hr
= _dw_factory
->CreateTextFormat(metric_family_name(_context
->outline_metrics
),
197 static_cast<DWRITE_FONT_WEIGHT
>(_context
->outline_metrics
->otmTextMetrics
.tmWeight
),
199 static_cast<DWRITE_FONT_STRETCH
>(os2_metrics
->get_usWidthClass()),
205 hr
= dw_text_format
->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP
);
208 CComPtr
<IDWriteTextLayout
> dw_text_layout
;
209 if (_dw_measuring_mode
== DWRITE_MEASURING_MODE_NATURAL
)
211 hr
= _dw_factory
->CreateTextLayout(lpString
,
214 static_cast<FLOAT
>(_context
->bmp_header
.biWidth
),
220 hr
= _dw_factory
->CreateGdiCompatibleTextLayout(lpString
,
223 static_cast<FLOAT
>(_context
->bmp_header
.biWidth
),
232 UINT glyph_run_start
= 0;
234 void *drawing_context
[3] = {&new_glyph_run
, &glyph_run_start
, &draw_success
};
235 hr
= dw_text_layout
->Draw(drawing_context
, this, 0, 0);
237 assert(glyph_run_start
== c
);
242 bool dw_renderer::render(bool is_glyph_index
, bool is_pdy
, LPCWSTR lpString
, UINT c
, CONST INT
*lpDx
, glyph_run
&new_glyph_run
)
246 const BYTE dx_skip
= (is_pdy
? 2 : 1);
248 for (UINT i
= 0; i
< c
; ++i
)
249 _advances
[i
] = static_cast<FLOAT
>(lpDx
[i
* dx_skip
]);// - 0.1f; // small adjustment to emulate GDI metrics
253 return render_glyph(lpString
, c
, new_glyph_run
);
255 return render_text(lpString
, c
, new_glyph_run
);
261 // These methods are never called in this scenario so we just use stub
264 IFACEMETHODIMP
dw_renderer::QueryInterface(
265 /* [in] */ REFIID riid
,
266 /* [iid_is][out] */ __RPC__deref_out
void __RPC_FAR
*__RPC_FAR
*ppvObject
272 IFACEMETHODIMP_(ULONG
) dw_renderer::AddRef( void)
277 IFACEMETHODIMP_(ULONG
) dw_renderer::Release( void)
282 /******************************************************************
284 * dw_renderer::IsPixelSnappingDisabled *
286 * Determines whether pixel snapping is disabled. The recommended *
287 * default is FALSE, unless doing animation that requires *
288 * subpixel vertical placement. *
290 ******************************************************************/
292 IFACEMETHODIMP
dw_renderer::IsPixelSnappingDisabled(
293 __maybenull
void* clientDrawingContext
,
294 __out BOOL
* isDisabled
302 /******************************************************************
304 * dw_renderer::GetCurrentTransform *
306 * Returns the current transform applied to the render target.. *
308 ******************************************************************/
310 IFACEMETHODIMP
dw_renderer::GetCurrentTransform(
311 __maybenull
void* clientDrawingContext
,
312 __out DWRITE_MATRIX
* transform
320 /******************************************************************
322 * dw_renderer::GetPixelsPerDip *
324 * This returns the number of pixels per DIP. *
326 ******************************************************************/
328 IFACEMETHODIMP
dw_renderer::GetPixelsPerDip(
329 __maybenull
void* clientDrawingContext
,
330 __out FLOAT
* pixelsPerDip
333 *pixelsPerDip
= _pixels_per_dip
;
338 /******************************************************************
340 * dw_renderer::DrawGlyphRun *
342 * Gets GlyphRun outlines via IDWriteFontFace::GetGlyphRunOutline *
343 * and then draws and fills them using Direct2D path geometries *
345 ******************************************************************/
347 IFACEMETHODIMP
dw_renderer::DrawGlyphRun(
348 __maybenull
void* clientDrawingContext
,
349 FLOAT baselineOriginX
,
350 FLOAT baselineOriginY
,
351 DWRITE_MEASURING_MODE measuringMode
,
352 __in DWRITE_GLYPH_RUN
const* glyphRun
,
353 __in DWRITE_GLYPH_RUN_DESCRIPTION
const* glyphRunDescription
,
354 __maybenull IUnknown
* clientDrawingEffect
357 void **drawing_context
= static_cast<void **>(clientDrawingContext
);
358 glyph_run
*new_glyph_run
= static_cast<glyph_run
*>(drawing_context
[0]);
359 UINT
*glyph_run_start
= static_cast<UINT
*>(drawing_context
[1]);
360 bool *draw_success
= static_cast<bool *>(drawing_context
[2]);
362 if (_advances
.empty())
363 *draw_success
&= make_glyph_texture(baselineOriginX
, 0, glyphRun
, new_glyph_run
);
366 DWRITE_GLYPH_RUN final_glyph_run
= *glyphRun
;
367 final_glyph_run
.glyphAdvances
= &_advances
[*glyph_run_start
];
369 *draw_success
&= make_glyph_texture(baselineOriginX
, 0, &final_glyph_run
, new_glyph_run
);
372 *glyph_run_start
+= glyphRunDescription
->stringLength
;
377 /******************************************************************
379 * dw_renderer::DrawUnderline *
381 * This function is not implemented for the purposes of this *
384 ******************************************************************/
386 IFACEMETHODIMP
dw_renderer::DrawUnderline(
387 __maybenull
void* clientDrawingContext
,
388 FLOAT baselineOriginX
,
389 FLOAT baselineOriginY
,
390 __in DWRITE_UNDERLINE
const* underline
,
391 __maybenull IUnknown
* clientDrawingEffect
397 /******************************************************************
399 * dw_renderer::DrawStrikethrough *
401 * This function is not implemented for the purposes of this *
404 ******************************************************************/
406 IFACEMETHODIMP
dw_renderer::DrawStrikethrough(
407 __maybenull
void* clientDrawingContext
,
408 FLOAT baselineOriginX
,
409 FLOAT baselineOriginY
,
410 __in DWRITE_STRIKETHROUGH
const* strikethrough
,
411 __maybenull IUnknown
* clientDrawingEffect
417 /******************************************************************
419 * dw_renderer::DrawInlineObject *
421 * This function is not implemented for the purposes of this *
424 ******************************************************************/
426 IFACEMETHODIMP
dw_renderer::DrawInlineObject(
427 __maybenull
void* clientDrawingContext
,
430 IDWriteInlineObject
* inlineObject
,
433 __maybenull IUnknown
* clientDrawingEffect