winebuild: Use strarray objects instead of pointers where possible.
[wine.git] / dlls / dwrite / gdiinterop.c
blobdcc2f7abb2263846467cb0be7a2f3d9ba25c5b61
1 /*
2 * GDI Interop
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "dwrite_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
35 struct gdiinterop {
36 IDWriteGdiInterop IDWriteGdiInterop_iface;
37 IDWriteFactory2 *factory;
40 struct dib_data {
41 DWORD *ptr;
42 int stride;
43 int width;
46 struct rendertarget {
47 IDWriteBitmapRenderTarget1 IDWriteBitmapRenderTarget1_iface;
48 ID2D1SimplifiedGeometrySink ID2D1SimplifiedGeometrySink_iface;
49 LONG ref;
51 IDWriteFactory *factory;
52 DWRITE_TEXT_ANTIALIAS_MODE antialiasmode;
53 FLOAT ppdip;
54 DWRITE_MATRIX m;
55 SIZE size;
56 HDC hdc;
57 struct dib_data dib;
60 static inline int get_dib_stride(int width, int bpp)
62 return ((width * bpp + 31) >> 3) & ~3;
65 static HRESULT create_target_dibsection(struct rendertarget *target, UINT32 width, UINT32 height)
67 char bmibuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
68 BITMAPINFO *bmi = (BITMAPINFO*)bmibuf;
69 HBITMAP hbm;
71 target->size.cx = width;
72 target->size.cy = height;
74 memset(bmi, 0, sizeof(bmibuf));
75 bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
76 bmi->bmiHeader.biHeight = -height;
77 bmi->bmiHeader.biWidth = width;
78 bmi->bmiHeader.biBitCount = 32;
79 bmi->bmiHeader.biPlanes = 1;
80 bmi->bmiHeader.biCompression = BI_RGB;
82 hbm = CreateDIBSection(target->hdc, bmi, DIB_RGB_COLORS, (void**)&target->dib.ptr, NULL, 0);
83 if (!hbm) {
84 hbm = CreateBitmap(1, 1, 1, 1, NULL);
85 target->dib.ptr = NULL;
86 target->dib.stride = 0;
87 target->dib.width = 0;
89 else {
90 target->dib.stride = get_dib_stride(width, 32);
91 target->dib.width = width;
94 DeleteObject(SelectObject(target->hdc, hbm));
95 return S_OK;
98 static inline struct rendertarget *impl_from_IDWriteBitmapRenderTarget1(IDWriteBitmapRenderTarget1 *iface)
100 return CONTAINING_RECORD(iface, struct rendertarget, IDWriteBitmapRenderTarget1_iface);
103 static inline struct rendertarget *impl_from_ID2D1SimplifiedGeometrySink(ID2D1SimplifiedGeometrySink *iface)
105 return CONTAINING_RECORD(iface, struct rendertarget, ID2D1SimplifiedGeometrySink_iface);
108 static inline struct gdiinterop *impl_from_IDWriteGdiInterop(IDWriteGdiInterop *iface)
110 return CONTAINING_RECORD(iface, struct gdiinterop, IDWriteGdiInterop_iface);
113 static HRESULT WINAPI rendertarget_sink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **obj)
115 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
116 IsEqualIID(riid, &IID_IUnknown))
118 *obj = iface;
119 ID2D1SimplifiedGeometrySink_AddRef(iface);
120 return S_OK;
123 *obj = NULL;
125 return E_NOINTERFACE;
128 static ULONG WINAPI rendertarget_sink_AddRef(ID2D1SimplifiedGeometrySink *iface)
130 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
131 return IDWriteBitmapRenderTarget1_AddRef(&This->IDWriteBitmapRenderTarget1_iface);
134 static ULONG WINAPI rendertarget_sink_Release(ID2D1SimplifiedGeometrySink *iface)
136 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
137 return IDWriteBitmapRenderTarget1_Release(&This->IDWriteBitmapRenderTarget1_iface);
140 static void WINAPI rendertarget_sink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
142 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
143 SetPolyFillMode(This->hdc, mode == D2D1_FILL_MODE_ALTERNATE ? ALTERNATE : WINDING);
146 static void WINAPI rendertarget_sink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT vertexFlags)
150 static void WINAPI rendertarget_sink_BeginFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
152 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
153 MoveToEx(This->hdc, startPoint.x, startPoint.y, NULL);
156 static void WINAPI rendertarget_sink_AddLines(ID2D1SimplifiedGeometrySink *iface, const D2D1_POINT_2F *points, UINT32 count)
158 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
160 while (count--) {
161 LineTo(This->hdc, points->x, points->y);
162 points++;
166 static void WINAPI rendertarget_sink_AddBeziers(ID2D1SimplifiedGeometrySink *iface, const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
168 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
169 POINT points[3];
171 while (count--) {
172 points[0].x = beziers->point1.x;
173 points[0].y = beziers->point1.y;
174 points[1].x = beziers->point2.x;
175 points[1].y = beziers->point2.y;
176 points[2].x = beziers->point3.x;
177 points[2].y = beziers->point3.y;
179 PolyBezierTo(This->hdc, points, 3);
180 beziers++;
184 static void WINAPI rendertarget_sink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
186 struct rendertarget *This = impl_from_ID2D1SimplifiedGeometrySink(iface);
187 CloseFigure(This->hdc);
190 static HRESULT WINAPI rendertarget_sink_Close(ID2D1SimplifiedGeometrySink *iface)
192 return S_OK;
195 static const ID2D1SimplifiedGeometrySinkVtbl rendertargetsinkvtbl = {
196 rendertarget_sink_QueryInterface,
197 rendertarget_sink_AddRef,
198 rendertarget_sink_Release,
199 rendertarget_sink_SetFillMode,
200 rendertarget_sink_SetSegmentFlags,
201 rendertarget_sink_BeginFigure,
202 rendertarget_sink_AddLines,
203 rendertarget_sink_AddBeziers,
204 rendertarget_sink_EndFigure,
205 rendertarget_sink_Close
208 static HRESULT WINAPI rendertarget_QueryInterface(IDWriteBitmapRenderTarget1 *iface, REFIID riid, void **obj)
210 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
212 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
214 if (IsEqualIID(riid, &IID_IDWriteBitmapRenderTarget1) ||
215 IsEqualIID(riid, &IID_IDWriteBitmapRenderTarget) ||
216 IsEqualIID(riid, &IID_IUnknown))
218 *obj = iface;
219 IDWriteBitmapRenderTarget1_AddRef(iface);
220 return S_OK;
223 *obj = NULL;
225 return E_NOINTERFACE;
228 static ULONG WINAPI rendertarget_AddRef(IDWriteBitmapRenderTarget1 *iface)
230 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
231 ULONG ref = InterlockedIncrement(&This->ref);
232 TRACE("(%p)->(%d)\n", This, ref);
233 return ref;
236 static ULONG WINAPI rendertarget_Release(IDWriteBitmapRenderTarget1 *iface)
238 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
239 ULONG ref = InterlockedDecrement(&This->ref);
241 TRACE("(%p)->(%d)\n", This, ref);
243 if (!ref)
245 IDWriteFactory_Release(This->factory);
246 DeleteDC(This->hdc);
247 heap_free(This);
250 return ref;
253 static inline DWORD *get_pixel_ptr_32(struct dib_data *dib, int x, int y)
255 return (DWORD *)((BYTE*)dib->ptr + y * dib->stride + x * 4);
258 static void blit_8(struct dib_data *dib, const BYTE *src, const RECT *rect, DWORD text_pixel)
260 DWORD *dst_ptr = get_pixel_ptr_32(dib, rect->left, rect->top);
261 int x, y, src_width = rect->right - rect->left;
263 for (y = rect->top; y < rect->bottom; y++) {
264 for (x = 0; x < src_width; x++) {
265 if (src[x] < DWRITE_ALPHA_MAX) continue;
266 dst_ptr[x] = text_pixel;
269 src += src_width;
270 dst_ptr += dib->stride / 4;
274 static inline BYTE blend_color(BYTE dst, BYTE src, BYTE alpha)
276 return (src * alpha + dst * (255 - alpha) + 127) / 255;
279 static inline DWORD blend_subpixel(BYTE r, BYTE g, BYTE b, DWORD text, const BYTE *alpha)
281 return blend_color(r, text >> 16, alpha[0]) << 16 |
282 blend_color(g, text >> 8, alpha[1]) << 8 |
283 blend_color(b, text, alpha[2]);
286 static void blit_subpixel_888(struct dib_data *dib, int dib_width, const BYTE *src,
287 const RECT *rect, DWORD text_pixel)
289 DWORD *dst_ptr = get_pixel_ptr_32(dib, rect->left, rect->top);
290 int x, y, src_width = rect->right - rect->left;
292 for (y = rect->top; y < rect->bottom; y++) {
293 for (x = 0; x < src_width; x++) {
294 if (src[3*x] == 0 && src[3*x+1] == 0 && src[3*x+2] == 0) continue;
295 dst_ptr[x] = blend_subpixel(dst_ptr[x] >> 16, dst_ptr[x] >> 8, dst_ptr[x], text_pixel, &src[3*x]);
297 dst_ptr += dib->stride / 4;
298 src += src_width * 3;
302 static inline DWORD colorref_to_pixel_888(COLORREF color)
304 return (((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000));
307 static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *iface,
308 FLOAT originX, FLOAT originY, DWRITE_MEASURING_MODE measuring_mode,
309 DWRITE_GLYPH_RUN const *run, IDWriteRenderingParams *params, COLORREF color,
310 RECT *bbox_ret)
312 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
313 IDWriteGlyphRunAnalysis *analysis;
314 DWRITE_RENDERING_MODE rendermode;
315 DWRITE_TEXTURE_TYPE texturetype;
316 IDWriteFontFace1 *fontface1;
317 RECT target, bounds;
318 HRESULT hr;
320 TRACE("(%p)->(%.2f %.2f %d %p %p 0x%08x %p)\n", This, originX, originY,
321 measuring_mode, run, params, color, bbox_ret);
323 SetRectEmpty(bbox_ret);
325 if (!This->dib.ptr)
326 return S_OK;
328 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
329 if (hr == S_OK) {
330 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, run->fontEmSize, This->ppdip * 96.0f,
331 This->ppdip * 96.0f, NULL, run->isSideways, DWRITE_OUTLINE_THRESHOLD_ALIASED, measuring_mode,
332 &rendermode);
333 IDWriteFontFace1_Release(fontface1);
335 else
336 hr = IDWriteFontFace_GetRecommendedRenderingMode(run->fontFace, run->fontEmSize,
337 This->ppdip, measuring_mode, params, &rendermode);
339 if (FAILED(hr))
340 return hr;
342 target.left = target.top = 0;
343 target.right = This->size.cx;
344 target.bottom = This->size.cy;
346 if (rendermode == DWRITE_RENDERING_MODE_OUTLINE) {
347 static const XFORM identity = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
348 const DWRITE_MATRIX *m = &This->m;
349 XFORM xform;
351 /* target allows any transform to be set, filter it here */
352 if (m->m11 * m->m22 == m->m12 * m->m21) {
353 xform.eM11 = 1.0f;
354 xform.eM12 = 0.0f;
355 xform.eM21 = 0.0f;
356 xform.eM22 = 1.0f;
357 xform.eDx = originX;
358 xform.eDy = originY;
359 } else {
360 xform.eM11 = m->m11;
361 xform.eM12 = m->m12;
362 xform.eM21 = m->m21;
363 xform.eM22 = m->m22;
364 xform.eDx = m->m11 * originX + m->m21 * originY + m->dx;
365 xform.eDy = m->m12 * originX + m->m22 * originY + m->dy;
367 SetWorldTransform(This->hdc, &xform);
369 BeginPath(This->hdc);
371 hr = IDWriteFontFace_GetGlyphRunOutline(run->fontFace, run->fontEmSize * This->ppdip,
372 run->glyphIndices, run->glyphAdvances, run->glyphOffsets, run->glyphCount,
373 run->isSideways, run->bidiLevel & 1, &This->ID2D1SimplifiedGeometrySink_iface);
375 EndPath(This->hdc);
377 if (hr == S_OK) {
378 HBRUSH brush = CreateSolidBrush(color);
380 SelectObject(This->hdc, brush);
382 FillPath(This->hdc);
384 /* FIXME: one way to get affected rectangle bounds is to use region fill */
385 if (bbox_ret)
386 *bbox_ret = target;
388 DeleteObject(brush);
391 SetWorldTransform(This->hdc, &identity);
393 return hr;
396 hr = IDWriteFactory_CreateGlyphRunAnalysis(This->factory,
397 run, This->ppdip, &This->m, rendermode, measuring_mode,
398 originX, originY, &analysis);
399 if (FAILED(hr)) {
400 WARN("failed to create analysis instance, 0x%08x\n", hr);
401 return hr;
404 SetRectEmpty(&bounds);
405 texturetype = DWRITE_TEXTURE_ALIASED_1x1;
406 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
407 if (FAILED(hr) || IsRectEmpty(&bounds)) {
408 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
409 if (FAILED(hr)) {
410 WARN("GetAlphaTextureBounds() failed, 0x%08x\n", hr);
411 IDWriteGlyphRunAnalysis_Release(analysis);
412 return hr;
414 texturetype = DWRITE_TEXTURE_CLEARTYPE_3x1;
417 if (IntersectRect(&target, &target, &bounds)) {
418 UINT32 size = (target.right - target.left) * (target.bottom - target.top);
419 BYTE *bitmap;
421 color = colorref_to_pixel_888(color);
422 if (texturetype == DWRITE_TEXTURE_CLEARTYPE_3x1)
423 size *= 3;
424 bitmap = heap_alloc_zero(size);
425 if (!bitmap) {
426 IDWriteGlyphRunAnalysis_Release(analysis);
427 return E_OUTOFMEMORY;
430 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, texturetype, &target, bitmap, size);
431 if (hr == S_OK) {
432 /* blit to target dib */
433 if (texturetype == DWRITE_TEXTURE_ALIASED_1x1)
434 blit_8(&This->dib, bitmap, &target, color);
435 else
436 blit_subpixel_888(&This->dib, This->size.cx, bitmap, &target, color);
438 if (bbox_ret) *bbox_ret = target;
441 heap_free(bitmap);
444 IDWriteGlyphRunAnalysis_Release(analysis);
446 return S_OK;
449 static HDC WINAPI rendertarget_GetMemoryDC(IDWriteBitmapRenderTarget1 *iface)
451 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
452 TRACE("(%p)\n", This);
453 return This->hdc;
456 static FLOAT WINAPI rendertarget_GetPixelsPerDip(IDWriteBitmapRenderTarget1 *iface)
458 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
459 TRACE("(%p)\n", This);
460 return This->ppdip;
463 static HRESULT WINAPI rendertarget_SetPixelsPerDip(IDWriteBitmapRenderTarget1 *iface, FLOAT ppdip)
465 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
467 TRACE("(%p)->(%.2f)\n", This, ppdip);
469 if (ppdip <= 0.0f)
470 return E_INVALIDARG;
472 This->ppdip = ppdip;
473 return S_OK;
476 static HRESULT WINAPI rendertarget_GetCurrentTransform(IDWriteBitmapRenderTarget1 *iface, DWRITE_MATRIX *transform)
478 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
480 TRACE("(%p)->(%p)\n", This, transform);
482 *transform = This->m;
483 return S_OK;
486 static HRESULT WINAPI rendertarget_SetCurrentTransform(IDWriteBitmapRenderTarget1 *iface, DWRITE_MATRIX const *transform)
488 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
490 TRACE("(%p)->(%p)\n", This, transform);
492 This->m = transform ? *transform : identity;
493 return S_OK;
496 static HRESULT WINAPI rendertarget_GetSize(IDWriteBitmapRenderTarget1 *iface, SIZE *size)
498 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
500 TRACE("(%p)->(%p)\n", This, size);
501 *size = This->size;
502 return S_OK;
505 static HRESULT WINAPI rendertarget_Resize(IDWriteBitmapRenderTarget1 *iface, UINT32 width, UINT32 height)
507 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
509 TRACE("(%p)->(%u %u)\n", This, width, height);
511 if (This->size.cx == width && This->size.cy == height)
512 return S_OK;
514 return create_target_dibsection(This, width, height);
517 static DWRITE_TEXT_ANTIALIAS_MODE WINAPI rendertarget_GetTextAntialiasMode(IDWriteBitmapRenderTarget1 *iface)
519 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
520 TRACE("(%p)\n", This);
521 return This->antialiasmode;
524 static HRESULT WINAPI rendertarget_SetTextAntialiasMode(IDWriteBitmapRenderTarget1 *iface, DWRITE_TEXT_ANTIALIAS_MODE mode)
526 struct rendertarget *This = impl_from_IDWriteBitmapRenderTarget1(iface);
528 TRACE("(%p)->(%d)\n", This, mode);
530 if ((DWORD)mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
531 return E_INVALIDARG;
533 This->antialiasmode = mode;
534 return S_OK;
537 static const IDWriteBitmapRenderTarget1Vtbl rendertargetvtbl = {
538 rendertarget_QueryInterface,
539 rendertarget_AddRef,
540 rendertarget_Release,
541 rendertarget_DrawGlyphRun,
542 rendertarget_GetMemoryDC,
543 rendertarget_GetPixelsPerDip,
544 rendertarget_SetPixelsPerDip,
545 rendertarget_GetCurrentTransform,
546 rendertarget_SetCurrentTransform,
547 rendertarget_GetSize,
548 rendertarget_Resize,
549 rendertarget_GetTextAntialiasMode,
550 rendertarget_SetTextAntialiasMode
553 static HRESULT create_rendertarget(IDWriteFactory *factory, HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget **ret)
555 struct rendertarget *target;
556 HRESULT hr;
558 *ret = NULL;
560 target = heap_alloc(sizeof(struct rendertarget));
561 if (!target) return E_OUTOFMEMORY;
563 target->IDWriteBitmapRenderTarget1_iface.lpVtbl = &rendertargetvtbl;
564 target->ID2D1SimplifiedGeometrySink_iface.lpVtbl = &rendertargetsinkvtbl;
565 target->ref = 1;
567 target->hdc = CreateCompatibleDC(hdc);
568 SetGraphicsMode(target->hdc, GM_ADVANCED);
569 hr = create_target_dibsection(target, width, height);
570 if (FAILED(hr)) {
571 IDWriteBitmapRenderTarget1_Release(&target->IDWriteBitmapRenderTarget1_iface);
572 return hr;
575 target->m = identity;
576 target->ppdip = GetDeviceCaps(target->hdc, LOGPIXELSX) / 96.0f;
577 target->antialiasmode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE;
578 target->factory = factory;
579 IDWriteFactory_AddRef(factory);
581 *ret = (IDWriteBitmapRenderTarget*)&target->IDWriteBitmapRenderTarget1_iface;
583 return S_OK;
586 static HRESULT WINAPI gdiinterop_QueryInterface(IDWriteGdiInterop *iface, REFIID riid, void **obj)
588 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
590 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
592 if (IsEqualIID(riid, &IID_IDWriteGdiInterop) ||
593 IsEqualIID(riid, &IID_IUnknown))
595 *obj = iface;
596 IDWriteGdiInterop_AddRef(iface);
597 return S_OK;
600 *obj = NULL;
601 return E_NOINTERFACE;
604 static ULONG WINAPI gdiinterop_AddRef(IDWriteGdiInterop *iface)
606 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
607 TRACE("(%p)\n", This);
608 return IDWriteFactory2_AddRef(This->factory);
611 static ULONG WINAPI gdiinterop_Release(IDWriteGdiInterop *iface)
613 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
614 TRACE("(%p)\n", This);
615 return IDWriteFactory2_Release(This->factory);
618 static HRESULT WINAPI gdiinterop_CreateFontFromLOGFONT(IDWriteGdiInterop *iface,
619 LOGFONTW const *logfont, IDWriteFont **font)
621 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
622 IDWriteFontCollection *collection;
623 IDWriteFontFamily *family;
624 DWRITE_FONT_STYLE style;
625 BOOL exists = FALSE;
626 UINT32 index;
627 HRESULT hr;
629 TRACE("(%p)->(%p %p)\n", This, logfont, font);
631 *font = NULL;
633 if (!logfont) return E_INVALIDARG;
635 hr = IDWriteFactory2_GetSystemFontCollection(This->factory, &collection, FALSE);
636 if (FAILED(hr)) {
637 ERR("failed to get system font collection: 0x%08x.\n", hr);
638 return hr;
641 hr = IDWriteFontCollection_FindFamilyName(collection, logfont->lfFaceName, &index, &exists);
642 if (FAILED(hr)) {
643 IDWriteFontCollection_Release(collection);
644 goto done;
647 if (!exists) {
648 hr = DWRITE_E_NOFONT;
649 goto done;
652 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
653 if (FAILED(hr))
654 goto done;
656 style = logfont->lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
657 hr = IDWriteFontFamily_GetFirstMatchingFont(family, logfont->lfWeight, DWRITE_FONT_STRETCH_NORMAL, style, font);
658 IDWriteFontFamily_Release(family);
660 done:
661 IDWriteFontCollection_Release(collection);
662 return hr;
665 static HRESULT WINAPI gdiinterop_ConvertFontToLOGFONT(IDWriteGdiInterop *iface,
666 IDWriteFont *font, LOGFONTW *logfont, BOOL *is_systemfont)
668 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
669 static const WCHAR enusW[] = {'e','n','-','u','s',0};
670 DWRITE_FONT_SIMULATIONS simulations;
671 IDWriteFontCollection *collection;
672 IDWriteLocalizedStrings *name;
673 IDWriteFontFamily *family;
674 DWRITE_FONT_STYLE style;
675 UINT32 index;
676 BOOL exists;
677 HRESULT hr;
679 TRACE("(%p)->(%p %p %p)\n", This, font, logfont, is_systemfont);
681 *is_systemfont = FALSE;
683 memset(logfont, 0, sizeof(*logfont));
685 if (!font)
686 return E_INVALIDARG;
688 hr = IDWriteFont_GetFontFamily(font, &family);
689 if (FAILED(hr))
690 return hr;
692 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
693 IDWriteFontFamily_Release(family);
694 if (FAILED(hr))
695 return hr;
697 *is_systemfont = is_system_collection(collection);
698 IDWriteFontCollection_Release(collection);
700 simulations = IDWriteFont_GetSimulations(font);
701 style = IDWriteFont_GetStyle(font);
703 logfont->lfCharSet = DEFAULT_CHARSET;
704 logfont->lfWeight = IDWriteFont_GetWeight(font);
705 logfont->lfItalic = style == DWRITE_FONT_STYLE_ITALIC || (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE);
706 logfont->lfOutPrecision = OUT_OUTLINE_PRECIS;
707 logfont->lfFaceName[0] = 0;
709 exists = FALSE;
710 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &name, &exists);
711 if (FAILED(hr) || !exists)
712 return hr;
714 hr = IDWriteLocalizedStrings_FindLocaleName(name, enusW, &index, &exists);
715 if (hr == S_OK)
716 hr = IDWriteLocalizedStrings_GetString(name, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
717 IDWriteLocalizedStrings_Release(name);
718 return hr;
721 static HRESULT WINAPI gdiinterop_ConvertFontFaceToLOGFONT(IDWriteGdiInterop *iface,
722 IDWriteFontFace *fontface, LOGFONTW *logfont)
724 static const WCHAR enusW[] = {'e','n','-','u','s',0};
725 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
726 IDWriteLocalizedStrings *familynames;
727 DWRITE_FONT_SIMULATIONS simulations;
728 DWRITE_FONT_FACE_TYPE face_type;
729 struct dwrite_font_props props;
730 IDWriteFontFileStream *stream;
731 IDWriteFontFile *file = NULL;
732 UINT32 index;
733 BOOL exists;
734 HRESULT hr;
736 TRACE("(%p)->(%p %p)\n", This, fontface, logfont);
738 memset(logfont, 0, sizeof(*logfont));
740 index = 1;
741 hr = IDWriteFontFace_GetFiles(fontface, &index, &file);
742 if (FAILED(hr) || !file)
743 return hr;
745 hr = get_filestream_from_file(file, &stream);
746 if (FAILED(hr)) {
747 IDWriteFontFile_Release(file);
748 return hr;
751 index = IDWriteFontFace_GetIndex(fontface);
752 face_type = IDWriteFontFace_GetType(fontface);
753 opentype_get_font_properties(stream, face_type, index, &props);
754 hr = opentype_get_font_familyname(stream, index, face_type, &familynames);
755 IDWriteFontFile_Release(file);
756 IDWriteFontFileStream_Release(stream);
757 if (FAILED(hr))
758 return hr;
760 simulations = IDWriteFontFace_GetSimulations(fontface);
762 logfont->lfCharSet = DEFAULT_CHARSET;
763 logfont->lfWeight = props.weight;
764 logfont->lfItalic = props.style == DWRITE_FONT_STYLE_ITALIC || (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE);
765 logfont->lfOutPrecision = OUT_OUTLINE_PRECIS;
766 logfont->lfFaceName[0] = 0;
768 exists = FALSE;
769 hr = IDWriteLocalizedStrings_FindLocaleName(familynames, enusW, &index, &exists);
770 if (FAILED(hr) || !exists) {
771 /* fallback to 0 index */
772 if (IDWriteLocalizedStrings_GetCount(familynames) > 0)
773 index = 0;
774 else {
775 IDWriteLocalizedStrings_Release(familynames);
776 return E_FAIL;
780 hr = IDWriteLocalizedStrings_GetString(familynames, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
781 IDWriteLocalizedStrings_Release(familynames);
783 return hr;
786 struct font_realization_info {
787 DWORD size;
788 DWORD flags;
789 DWORD cache_num;
790 DWORD instance_id;
791 DWORD unk;
792 WORD face_index;
793 WORD simulations;
796 struct font_fileinfo {
797 FILETIME writetime;
798 LARGE_INTEGER size;
799 WCHAR path[1];
802 /* Undocumented gdi32 exports, used to access actually selected font information */
803 extern BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info);
804 extern BOOL WINAPI GetFontFileInfo(DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed);
806 static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop *iface,
807 HDC hdc, IDWriteFontFace **fontface)
809 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
810 struct font_realization_info info;
811 struct font_fileinfo *fileinfo;
812 DWRITE_FONT_FILE_TYPE filetype;
813 DWRITE_FONT_FACE_TYPE facetype;
814 IDWriteFontFile *file;
815 BOOL is_supported;
816 UINT32 facenum;
817 DWORD needed;
818 HRESULT hr;
820 TRACE("(%p)->(%p %p)\n", This, hdc, fontface);
822 *fontface = NULL;
824 if (!hdc)
825 return E_INVALIDARG;
827 /* get selected font id */
828 info.size = sizeof(info);
829 if (!GetFontRealizationInfo(hdc, &info)) {
830 WARN("failed to get selected font id\n");
831 return E_FAIL;
834 needed = 0;
835 GetFontFileInfo(info.instance_id, 0, NULL, 0, &needed);
836 if (needed == 0) {
837 WARN("failed to get font file info size\n");
838 return E_FAIL;
841 fileinfo = heap_alloc(needed);
842 if (!fileinfo)
843 return E_OUTOFMEMORY;
845 if (!GetFontFileInfo(info.instance_id, 0, fileinfo, needed, &needed)) {
846 heap_free(fileinfo);
847 return E_FAIL;
850 hr = IDWriteFactory2_CreateFontFileReference(This->factory, fileinfo->path, &fileinfo->writetime,
851 &file);
852 heap_free(fileinfo);
853 if (FAILED(hr))
854 return hr;
856 is_supported = FALSE;
857 hr = IDWriteFontFile_Analyze(file, &is_supported, &filetype, &facetype, &facenum);
858 if (FAILED(hr) || !is_supported) {
859 IDWriteFontFile_Release(file);
860 return hr;
863 /* Simulations flags values match DWRITE_FONT_SIMULATIONS */
864 hr = IDWriteFactory2_CreateFontFace(This->factory, facetype, 1, &file, info.face_index, info.simulations,
865 fontface);
866 IDWriteFontFile_Release(file);
867 return hr;
870 static HRESULT WINAPI gdiinterop_CreateBitmapRenderTarget(IDWriteGdiInterop *iface,
871 HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget **target)
873 struct gdiinterop *This = impl_from_IDWriteGdiInterop(iface);
874 TRACE("(%p)->(%p %u %u %p)\n", This, hdc, width, height, target);
875 return create_rendertarget((IDWriteFactory*)This->factory, hdc, width, height, target);
878 static const struct IDWriteGdiInteropVtbl gdiinteropvtbl = {
879 gdiinterop_QueryInterface,
880 gdiinterop_AddRef,
881 gdiinterop_Release,
882 gdiinterop_CreateFontFromLOGFONT,
883 gdiinterop_ConvertFontToLOGFONT,
884 gdiinterop_ConvertFontFaceToLOGFONT,
885 gdiinterop_CreateFontFaceFromHdc,
886 gdiinterop_CreateBitmapRenderTarget
889 HRESULT create_gdiinterop(IDWriteFactory2 *factory, IDWriteGdiInterop **ret)
891 struct gdiinterop *This;
893 *ret = NULL;
895 This = heap_alloc(sizeof(struct gdiinterop));
896 if (!This) return E_OUTOFMEMORY;
898 This->IDWriteGdiInterop_iface.lpVtbl = &gdiinteropvtbl;
899 This->factory = factory;
901 *ret= &This->IDWriteGdiInterop_iface;
902 return S_OK;
905 void release_gdiinterop(IDWriteGdiInterop *iface)
907 struct gdiinterop *interop = impl_from_IDWriteGdiInterop(iface);
908 heap_free(interop);