wined3d: Use wined3d_texture_prepare_location() in surface_blt_fbo().
[wine.git] / dlls / dwrite / gdiinterop.c
blob84b463aea667aa5ba1069ee2216ac34c325d621d
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 IDWriteGdiInterop1 IDWriteGdiInterop1_iface;
37 IDWriteFactory3 *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_IDWriteGdiInterop1(IDWriteGdiInterop1 *iface)
110 return CONTAINING_RECORD(iface, struct gdiinterop, IDWriteGdiInterop1_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(IDWriteGdiInterop1 *iface, REFIID riid, void **obj)
588 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
590 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
592 if (IsEqualIID(riid, &IID_IDWriteGdiInterop1) ||
593 IsEqualIID(riid, &IID_IDWriteGdiInterop) ||
594 IsEqualIID(riid, &IID_IUnknown))
596 *obj = iface;
597 IDWriteGdiInterop1_AddRef(iface);
598 return S_OK;
601 *obj = NULL;
602 return E_NOINTERFACE;
605 static ULONG WINAPI gdiinterop_AddRef(IDWriteGdiInterop1 *iface)
607 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
608 TRACE("(%p)\n", This);
609 return IDWriteFactory3_AddRef(This->factory);
612 static ULONG WINAPI gdiinterop_Release(IDWriteGdiInterop1 *iface)
614 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
615 TRACE("(%p)\n", This);
616 return IDWriteFactory3_Release(This->factory);
619 static HRESULT WINAPI gdiinterop_CreateFontFromLOGFONT(IDWriteGdiInterop1 *iface,
620 LOGFONTW const *logfont, IDWriteFont **font)
622 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
624 TRACE("(%p)->(%p %p)\n", This, logfont, font);
626 return IDWriteGdiInterop1_CreateFontFromLOGFONT(iface, logfont, NULL, font);
629 static HRESULT WINAPI gdiinterop_ConvertFontToLOGFONT(IDWriteGdiInterop1 *iface,
630 IDWriteFont *font, LOGFONTW *logfont, BOOL *is_systemfont)
632 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
633 static const WCHAR enusW[] = {'e','n','-','u','s',0};
634 DWRITE_FONT_SIMULATIONS simulations;
635 IDWriteFontCollection *collection;
636 IDWriteLocalizedStrings *name;
637 IDWriteFontFamily *family;
638 DWRITE_FONT_STYLE style;
639 UINT32 index;
640 BOOL exists;
641 HRESULT hr;
643 TRACE("(%p)->(%p %p %p)\n", This, font, logfont, is_systemfont);
645 *is_systemfont = FALSE;
647 memset(logfont, 0, sizeof(*logfont));
649 if (!font)
650 return E_INVALIDARG;
652 hr = IDWriteFont_GetFontFamily(font, &family);
653 if (FAILED(hr))
654 return hr;
656 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
657 IDWriteFontFamily_Release(family);
658 if (FAILED(hr))
659 return hr;
661 *is_systemfont = is_system_collection(collection);
662 IDWriteFontCollection_Release(collection);
664 simulations = IDWriteFont_GetSimulations(font);
665 style = IDWriteFont_GetStyle(font);
667 logfont->lfCharSet = DEFAULT_CHARSET;
668 logfont->lfWeight = IDWriteFont_GetWeight(font);
669 logfont->lfItalic = style == DWRITE_FONT_STYLE_ITALIC || (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE);
670 logfont->lfOutPrecision = OUT_OUTLINE_PRECIS;
671 logfont->lfFaceName[0] = 0;
673 exists = FALSE;
674 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &name, &exists);
675 if (FAILED(hr) || !exists)
676 return hr;
678 hr = IDWriteLocalizedStrings_FindLocaleName(name, enusW, &index, &exists);
679 if (hr == S_OK)
680 hr = IDWriteLocalizedStrings_GetString(name, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
681 IDWriteLocalizedStrings_Release(name);
682 return hr;
685 static HRESULT WINAPI gdiinterop_ConvertFontFaceToLOGFONT(IDWriteGdiInterop1 *iface,
686 IDWriteFontFace *fontface, LOGFONTW *logfont)
688 static const WCHAR enusW[] = {'e','n','-','u','s',0};
689 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
690 IDWriteLocalizedStrings *familynames;
691 DWRITE_FONT_SIMULATIONS simulations;
692 DWRITE_FONT_FACE_TYPE face_type;
693 struct dwrite_font_props props;
694 IDWriteFontFileStream *stream;
695 IDWriteFontFile *file = NULL;
696 UINT32 index;
697 BOOL exists;
698 HRESULT hr;
700 TRACE("(%p)->(%p %p)\n", This, fontface, logfont);
702 memset(logfont, 0, sizeof(*logfont));
704 index = 1;
705 hr = IDWriteFontFace_GetFiles(fontface, &index, &file);
706 if (FAILED(hr) || !file)
707 return hr;
709 hr = get_filestream_from_file(file, &stream);
710 if (FAILED(hr)) {
711 IDWriteFontFile_Release(file);
712 return hr;
715 index = IDWriteFontFace_GetIndex(fontface);
716 face_type = IDWriteFontFace_GetType(fontface);
717 opentype_get_font_properties(stream, face_type, index, &props);
718 hr = opentype_get_font_familyname(stream, index, face_type, &familynames);
719 IDWriteFontFile_Release(file);
720 IDWriteFontFileStream_Release(stream);
721 if (FAILED(hr))
722 return hr;
724 simulations = IDWriteFontFace_GetSimulations(fontface);
726 logfont->lfCharSet = DEFAULT_CHARSET;
727 logfont->lfWeight = props.weight;
728 logfont->lfItalic = props.style == DWRITE_FONT_STYLE_ITALIC || (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE);
729 logfont->lfOutPrecision = OUT_OUTLINE_PRECIS;
730 logfont->lfFaceName[0] = 0;
732 exists = FALSE;
733 hr = IDWriteLocalizedStrings_FindLocaleName(familynames, enusW, &index, &exists);
734 if (FAILED(hr) || !exists) {
735 /* fallback to 0 index */
736 if (IDWriteLocalizedStrings_GetCount(familynames) > 0)
737 index = 0;
738 else {
739 IDWriteLocalizedStrings_Release(familynames);
740 return E_FAIL;
744 hr = IDWriteLocalizedStrings_GetString(familynames, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
745 IDWriteLocalizedStrings_Release(familynames);
747 return hr;
750 struct font_realization_info {
751 DWORD size;
752 DWORD flags;
753 DWORD cache_num;
754 DWORD instance_id;
755 DWORD unk;
756 WORD face_index;
757 WORD simulations;
760 struct font_fileinfo {
761 FILETIME writetime;
762 LARGE_INTEGER size;
763 WCHAR path[1];
766 /* Undocumented gdi32 exports, used to access actually selected font information */
767 extern BOOL WINAPI GetFontRealizationInfo(HDC hdc, struct font_realization_info *info);
768 extern BOOL WINAPI GetFontFileInfo(DWORD instance_id, DWORD unknown, struct font_fileinfo *info, DWORD size, DWORD *needed);
770 static HRESULT WINAPI gdiinterop_CreateFontFaceFromHdc(IDWriteGdiInterop1 *iface,
771 HDC hdc, IDWriteFontFace **fontface)
773 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
774 struct font_realization_info info;
775 struct font_fileinfo *fileinfo;
776 DWRITE_FONT_FILE_TYPE filetype;
777 DWRITE_FONT_FACE_TYPE facetype;
778 IDWriteFontFile *file;
779 BOOL is_supported;
780 UINT32 facenum;
781 DWORD needed;
782 HRESULT hr;
784 TRACE("(%p)->(%p %p)\n", This, hdc, fontface);
786 *fontface = NULL;
788 if (!hdc)
789 return E_INVALIDARG;
791 /* get selected font id */
792 info.size = sizeof(info);
793 if (!GetFontRealizationInfo(hdc, &info)) {
794 WARN("failed to get selected font id\n");
795 return E_FAIL;
798 needed = 0;
799 GetFontFileInfo(info.instance_id, 0, NULL, 0, &needed);
800 if (needed == 0) {
801 WARN("failed to get font file info size\n");
802 return E_FAIL;
805 fileinfo = heap_alloc(needed);
806 if (!fileinfo)
807 return E_OUTOFMEMORY;
809 if (!GetFontFileInfo(info.instance_id, 0, fileinfo, needed, &needed)) {
810 heap_free(fileinfo);
811 return E_FAIL;
814 hr = IDWriteFactory3_CreateFontFileReference(This->factory, fileinfo->path, &fileinfo->writetime,
815 &file);
816 heap_free(fileinfo);
817 if (FAILED(hr))
818 return hr;
820 is_supported = FALSE;
821 hr = IDWriteFontFile_Analyze(file, &is_supported, &filetype, &facetype, &facenum);
822 if (FAILED(hr) || !is_supported) {
823 IDWriteFontFile_Release(file);
824 return hr;
827 /* Simulations flags values match DWRITE_FONT_SIMULATIONS */
828 hr = IDWriteFactory3_CreateFontFace(This->factory, facetype, 1, &file, info.face_index, info.simulations,
829 fontface);
830 IDWriteFontFile_Release(file);
831 return hr;
834 static HRESULT WINAPI gdiinterop_CreateBitmapRenderTarget(IDWriteGdiInterop1 *iface,
835 HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget **target)
837 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
838 TRACE("(%p)->(%p %u %u %p)\n", This, hdc, width, height, target);
839 return create_rendertarget((IDWriteFactory*)This->factory, hdc, width, height, target);
842 static HRESULT WINAPI gdiinterop1_CreateFontFromLOGFONT(IDWriteGdiInterop1 *iface,
843 LOGFONTW const *logfont, IDWriteFontCollection *collection, IDWriteFont **font)
845 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
846 IDWriteFontFamily *family;
847 DWRITE_FONT_STYLE style;
848 BOOL exists = FALSE;
849 UINT32 index;
850 HRESULT hr;
852 TRACE("(%p)->(%p %p %p)\n", This, logfont, collection, font);
854 *font = NULL;
856 if (!logfont) return E_INVALIDARG;
858 if (collection)
859 IDWriteFontCollection_AddRef(collection);
860 else {
861 hr = IDWriteFactory2_GetSystemFontCollection((IDWriteFactory2*)This->factory, &collection, FALSE);
862 if (FAILED(hr)) {
863 ERR("failed to get system font collection: 0x%08x.\n", hr);
864 return hr;
868 hr = IDWriteFontCollection_FindFamilyName(collection, logfont->lfFaceName, &index, &exists);
869 if (FAILED(hr))
870 goto done;
872 if (!exists) {
873 hr = DWRITE_E_NOFONT;
874 goto done;
877 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
878 if (FAILED(hr))
879 goto done;
881 style = logfont->lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
882 hr = IDWriteFontFamily_GetFirstMatchingFont(family, logfont->lfWeight, DWRITE_FONT_STRETCH_NORMAL, style, font);
883 IDWriteFontFamily_Release(family);
885 done:
886 IDWriteFontCollection_Release(collection);
887 return hr;
890 static HRESULT WINAPI gdiinterop1_GetFontSignature_(IDWriteGdiInterop1 *iface, IDWriteFontFace *fontface,
891 FONTSIGNATURE *fontsig)
893 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
895 FIXME("(%p)->(%p %p): stub\n", This, fontface, fontsig);
897 return E_NOTIMPL;
900 static HRESULT WINAPI gdiinterop1_GetFontSignature(IDWriteGdiInterop1 *iface, IDWriteFont *font, FONTSIGNATURE *fontsig)
902 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
904 FIXME("(%p)->(%p %p): stub\n", This, font, fontsig);
906 return E_NOTIMPL;
909 static HRESULT WINAPI gdiinterop1_GetMatchingFontsByLOGFONT(IDWriteGdiInterop1 *iface, LOGFONTW const *logfont,
910 IDWriteFontSet *fontset, IDWriteFontSet **subset)
912 struct gdiinterop *This = impl_from_IDWriteGdiInterop1(iface);
914 FIXME("(%p)->(%p %p %p): stub\n", This, logfont, fontset, subset);
916 return E_NOTIMPL;
919 static const struct IDWriteGdiInterop1Vtbl gdiinteropvtbl = {
920 gdiinterop_QueryInterface,
921 gdiinterop_AddRef,
922 gdiinterop_Release,
923 gdiinterop_CreateFontFromLOGFONT,
924 gdiinterop_ConvertFontToLOGFONT,
925 gdiinterop_ConvertFontFaceToLOGFONT,
926 gdiinterop_CreateFontFaceFromHdc,
927 gdiinterop_CreateBitmapRenderTarget,
928 gdiinterop1_CreateFontFromLOGFONT,
929 gdiinterop1_GetFontSignature_,
930 gdiinterop1_GetFontSignature,
931 gdiinterop1_GetMatchingFontsByLOGFONT
934 HRESULT create_gdiinterop(IDWriteFactory3 *factory, IDWriteGdiInterop1 **ret)
936 struct gdiinterop *This;
938 *ret = NULL;
940 This = heap_alloc(sizeof(struct gdiinterop));
941 if (!This) return E_OUTOFMEMORY;
943 This->IDWriteGdiInterop1_iface.lpVtbl = &gdiinteropvtbl;
944 This->factory = factory;
946 *ret= &This->IDWriteGdiInterop1_iface;
947 return S_OK;
950 void release_gdiinterop(IDWriteGdiInterop1 *iface)
952 struct gdiinterop *interop = impl_from_IDWriteGdiInterop1(iface);
953 heap_free(interop);