1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include <windows.h>
8
9 #include <algorithm>
10 #include <memory>
11
12 #include "core/fxcrt/fx_system.h"
13 #include "core/fxge/cfx_gemodule.h"
14 #include "core/fxge/cfx_graphstatedata.h"
15 #include "core/fxge/cfx_pathdata.h"
16 #include "core/fxge/win32/cfx_windowsdib.h"
17 #include "core/fxge/win32/win32_int.h"
18 #include "third_party/base/ptr_util.h"
19
20 // Has to come before gdiplus.h
21 namespace Gdiplus {
22 using std::min;
23 using std::max;
24 } // namespace Gdiplus
25
26 #include <gdiplus.h> // NOLINT
27
28 using namespace Gdiplus; // NOLINT
29 using namespace Gdiplus::DllExports; // NOLINT
30
31 #define GdiFillType2Gdip(fill_type) \
32 (fill_type == ALTERNATE ? FillModeAlternate : FillModeWinding)
33
34 enum {
35 FuncId_GdipCreatePath2,
36 FuncId_GdipSetPenDashStyle,
37 FuncId_GdipSetPenDashArray,
38 FuncId_GdipSetPenDashCap197819,
39 FuncId_GdipSetPenLineJoin,
40 FuncId_GdipSetPenWidth,
41 FuncId_GdipCreateFromHDC,
42 FuncId_GdipSetPageUnit,
43 FuncId_GdipSetSmoothingMode,
44 FuncId_GdipCreateSolidFill,
45 FuncId_GdipFillPath,
46 FuncId_GdipDeleteBrush,
47 FuncId_GdipCreatePen1,
48 FuncId_GdipSetPenMiterLimit,
49 FuncId_GdipDrawPath,
50 FuncId_GdipDeletePen,
51 FuncId_GdipDeletePath,
52 FuncId_GdipDeleteGraphics,
53 FuncId_GdipCreateBitmapFromFileICM,
54 FuncId_GdipCreateBitmapFromStreamICM,
55 FuncId_GdipGetImageHeight,
56 FuncId_GdipGetImageWidth,
57 FuncId_GdipGetImagePixelFormat,
58 FuncId_GdipBitmapLockBits,
59 FuncId_GdipGetImagePaletteSize,
60 FuncId_GdipGetImagePalette,
61 FuncId_GdipBitmapUnlockBits,
62 FuncId_GdipDisposeImage,
63 FuncId_GdipFillRectangle,
64 FuncId_GdipCreateBitmapFromScan0,
65 FuncId_GdipSetImagePalette,
66 FuncId_GdipSetInterpolationMode,
67 FuncId_GdipDrawImagePointsI,
68 FuncId_GdipCreateBitmapFromGdiDib,
69 FuncId_GdiplusStartup,
70 FuncId_GdipDrawLineI,
71 FuncId_GdipResetClip,
72 FuncId_GdipCreatePath,
73 FuncId_GdipAddPathPath,
74 FuncId_GdipSetPathFillMode,
75 FuncId_GdipSetClipPath,
76 FuncId_GdipGetClip,
77 FuncId_GdipCreateRegion,
78 FuncId_GdipGetClipBoundsI,
79 FuncId_GdipSetClipRegion,
80 FuncId_GdipWidenPath,
81 FuncId_GdipAddPathLine,
82 FuncId_GdipAddPathRectangle,
83 FuncId_GdipDeleteRegion,
84 FuncId_GdipGetDC,
85 FuncId_GdipReleaseDC,
86 FuncId_GdipSetPenLineCap197819,
87 FuncId_GdipSetPenDashOffset,
88 FuncId_GdipResetPath,
89 FuncId_GdipCreateRegionPath,
90 FuncId_GdipCreateFont,
91 FuncId_GdipGetFontSize,
92 FuncId_GdipCreateFontFamilyFromName,
93 FuncId_GdipSetTextRenderingHint,
94 FuncId_GdipDrawDriverString,
95 FuncId_GdipCreateMatrix2,
96 FuncId_GdipDeleteMatrix,
97 FuncId_GdipSetWorldTransform,
98 FuncId_GdipResetWorldTransform,
99 FuncId_GdipDeleteFontFamily,
100 FuncId_GdipDeleteFont,
101 FuncId_GdipNewPrivateFontCollection,
102 FuncId_GdipDeletePrivateFontCollection,
103 FuncId_GdipPrivateAddMemoryFont,
104 FuncId_GdipGetFontCollectionFamilyList,
105 FuncId_GdipGetFontCollectionFamilyCount,
106 FuncId_GdipSetTextContrast,
107 FuncId_GdipSetPixelOffsetMode,
108 FuncId_GdipGetImageGraphicsContext,
109 FuncId_GdipDrawImageI,
110 FuncId_GdipDrawImageRectI,
111 FuncId_GdipDrawString,
112 FuncId_GdipSetPenTransform,
113 };
114 static LPCSTR g_GdipFuncNames[] = {
115 "GdipCreatePath2",
116 "GdipSetPenDashStyle",
117 "GdipSetPenDashArray",
118 "GdipSetPenDashCap197819",
119 "GdipSetPenLineJoin",
120 "GdipSetPenWidth",
121 "GdipCreateFromHDC",
122 "GdipSetPageUnit",
123 "GdipSetSmoothingMode",
124 "GdipCreateSolidFill",
125 "GdipFillPath",
126 "GdipDeleteBrush",
127 "GdipCreatePen1",
128 "GdipSetPenMiterLimit",
129 "GdipDrawPath",
130 "GdipDeletePen",
131 "GdipDeletePath",
132 "GdipDeleteGraphics",
133 "GdipCreateBitmapFromFileICM",
134 "GdipCreateBitmapFromStreamICM",
135 "GdipGetImageHeight",
136 "GdipGetImageWidth",
137 "GdipGetImagePixelFormat",
138 "GdipBitmapLockBits",
139 "GdipGetImagePaletteSize",
140 "GdipGetImagePalette",
141 "GdipBitmapUnlockBits",
142 "GdipDisposeImage",
143 "GdipFillRectangle",
144 "GdipCreateBitmapFromScan0",
145 "GdipSetImagePalette",
146 "GdipSetInterpolationMode",
147 "GdipDrawImagePointsI",
148 "GdipCreateBitmapFromGdiDib",
149 "GdiplusStartup",
150 "GdipDrawLineI",
151 "GdipResetClip",
152 "GdipCreatePath",
153 "GdipAddPathPath",
154 "GdipSetPathFillMode",
155 "GdipSetClipPath",
156 "GdipGetClip",
157 "GdipCreateRegion",
158 "GdipGetClipBoundsI",
159 "GdipSetClipRegion",
160 "GdipWidenPath",
161 "GdipAddPathLine",
162 "GdipAddPathRectangle",
163 "GdipDeleteRegion",
164 "GdipGetDC",
165 "GdipReleaseDC",
166 "GdipSetPenLineCap197819",
167 "GdipSetPenDashOffset",
168 "GdipResetPath",
169 "GdipCreateRegionPath",
170 "GdipCreateFont",
171 "GdipGetFontSize",
172 "GdipCreateFontFamilyFromName",
173 "GdipSetTextRenderingHint",
174 "GdipDrawDriverString",
175 "GdipCreateMatrix2",
176 "GdipDeleteMatrix",
177 "GdipSetWorldTransform",
178 "GdipResetWorldTransform",
179 "GdipDeleteFontFamily",
180 "GdipDeleteFont",
181 "GdipNewPrivateFontCollection",
182 "GdipDeletePrivateFontCollection",
183 "GdipPrivateAddMemoryFont",
184 "GdipGetFontCollectionFamilyList",
185 "GdipGetFontCollectionFamilyCount",
186 "GdipSetTextContrast",
187 "GdipSetPixelOffsetMode",
188 "GdipGetImageGraphicsContext",
189 "GdipDrawImageI",
190 "GdipDrawImageRectI",
191 "GdipDrawString",
192 "GdipSetPenTransform",
193 };
194 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePath2)(GDIPCONST GpPointF*,
195 GDIPCONST BYTE*,
196 INT,
197 GpFillMode,
198 GpPath** path);
199 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashStyle)(
200 GpPen* pen,
201 GpDashStyle dashstyle);
202 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashArray)(GpPen* pen,
203 GDIPCONST REAL* dash,
204 INT count);
205 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashCap197819)(
206 GpPen* pen,
207 GpDashCap dashCap);
208 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenLineJoin)(GpPen* pen,
209 GpLineJoin lineJoin);
210 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenWidth)(GpPen* pen, REAL width);
211 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFromHDC)(HDC hdc,
212 GpGraphics** graphics);
213 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPageUnit)(GpGraphics* graphics,
214 GpUnit unit);
215 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetSmoothingMode)(
216 GpGraphics* graphics,
217 SmoothingMode smoothingMode);
218 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateSolidFill)(ARGB color,
219 GpSolidFill** brush);
220 typedef GpStatus(WINGDIPAPI* FuncType_GdipFillPath)(GpGraphics* graphics,
221 GpBrush* brush,
222 GpPath* path);
223 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteBrush)(GpBrush* brush);
224 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePen1)(ARGB color,
225 REAL width,
226 GpUnit unit,
227 GpPen** pen);
228 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenMiterLimit)(GpPen* pen,
229 REAL miterLimit);
230 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawPath)(GpGraphics* graphics,
231 GpPen* pen,
232 GpPath* path);
233 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePen)(GpPen* pen);
234 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePath)(GpPath* path);
235 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteGraphics)(GpGraphics* graphics);
236 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromFileICM)(
237 GDIPCONST WCHAR* filename,
238 GpBitmap** bitmap);
239 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromStreamICM)(
240 IStream* stream,
241 GpBitmap** bitmap);
242 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageWidth)(GpImage* image,
243 UINT* width);
244 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageHeight)(GpImage* image,
245 UINT* height);
246 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePixelFormat)(
247 GpImage* image,
248 PixelFormat* format);
249 typedef GpStatus(WINGDIPAPI* FuncType_GdipBitmapLockBits)(
250 GpBitmap* bitmap,
251 GDIPCONST GpRect* rect,
252 UINT flags,
253 PixelFormat format,
254 BitmapData* lockedBitmapData);
255 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePalette)(
256 GpImage* image,
257 ColorPalette* palette,
258 INT size);
259 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImagePaletteSize)(GpImage* image,
260 INT* size);
261 typedef GpStatus(WINGDIPAPI* FuncType_GdipBitmapUnlockBits)(
262 GpBitmap* bitmap,
263 BitmapData* lockedBitmapData);
264 typedef GpStatus(WINGDIPAPI* FuncType_GdipDisposeImage)(GpImage* image);
265 typedef GpStatus(WINGDIPAPI* FuncType_GdipFillRectangle)(GpGraphics* graphics,
266 GpBrush* brush,
267 REAL x,
268 REAL y,
269 REAL width,
270 REAL height);
271 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromScan0)(
272 INT width,
273 INT height,
274 INT stride,
275 PixelFormat format,
276 BYTE* scan0,
277 GpBitmap** bitmap);
278 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetImagePalette)(
279 GpImage* image,
280 GDIPCONST ColorPalette* palette);
281 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetInterpolationMode)(
282 GpGraphics* graphics,
283 InterpolationMode interpolationMode);
284 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImagePointsI)(
285 GpGraphics* graphics,
286 GpImage* image,
287 GDIPCONST GpPoint* dstpoints,
288 INT count);
289 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateBitmapFromGdiDib)(
290 GDIPCONST BITMAPINFO* gdiBitmapInfo,
291 VOID* gdiBitmapData,
292 GpBitmap** bitmap);
293 typedef Status(WINAPI* FuncType_GdiplusStartup)(
294 OUT uintptr_t* token,
295 const GdiplusStartupInput* input,
296 OUT GdiplusStartupOutput* output);
297 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawLineI)(GpGraphics* graphics,
298 GpPen* pen,
299 int x1,
300 int y1,
301 int x2,
302 int y2);
303 typedef GpStatus(WINGDIPAPI* FuncType_GdipResetClip)(GpGraphics* graphics);
304 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreatePath)(GpFillMode brushMode,
305 GpPath** path);
306 typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathPath)(
307 GpPath* path,
308 GDIPCONST GpPath* addingPath,
309 BOOL connect);
310 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPathFillMode)(GpPath* path,
311 GpFillMode fillmode);
312 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetClipPath)(GpGraphics* graphics,
313 GpPath* path,
314 CombineMode combineMode);
315 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetClip)(GpGraphics* graphics,
316 GpRegion* region);
317 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateRegion)(GpRegion** region);
318 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetClipBoundsI)(GpGraphics* graphics,
319 GpRect* rect);
320 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetClipRegion)(
321 GpGraphics* graphics,
322 GpRegion* region,
323 CombineMode combineMode);
324 typedef GpStatus(WINGDIPAPI* FuncType_GdipWidenPath)(GpPath* nativePath,
325 GpPen* pen,
326 GpMatrix* matrix,
327 REAL flatness);
328 typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathLine)(GpPath* path,
329 REAL x1,
330 REAL y1,
331 REAL x2,
332 REAL y2);
333 typedef GpStatus(WINGDIPAPI* FuncType_GdipAddPathRectangle)(GpPath* path,
334 REAL x,
335 REAL y,
336 REAL width,
337 REAL height);
338 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteRegion)(GpRegion* region);
339 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetDC)(GpGraphics* graphics,
340 HDC* hdc);
341 typedef GpStatus(WINGDIPAPI* FuncType_GdipReleaseDC)(GpGraphics* graphics,
342 HDC hdc);
343 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenLineCap197819)(
344 GpPen* pen,
345 GpLineCap startCap,
346 GpLineCap endCap,
347 GpDashCap dashCap);
348 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenDashOffset)(GpPen* pen,
349 REAL offset);
350 typedef GpStatus(WINGDIPAPI* FuncType_GdipResetPath)(GpPath* path);
351 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateRegionPath)(GpPath* path,
352 GpRegion** region);
353 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFont)(
354 GDIPCONST GpFontFamily* fontFamily,
355 REAL emSize,
356 INT style,
357 Unit unit,
358 GpFont** font);
359 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontSize)(GpFont* font,
360 REAL* size);
361 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateFontFamilyFromName)(
362 GDIPCONST WCHAR* name,
363 GpFontCollection* fontCollection,
364 GpFontFamily** FontFamily);
365 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetTextRenderingHint)(
366 GpGraphics* graphics,
367 TextRenderingHint mode);
368 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawDriverString)(
369 GpGraphics* graphics,
370 GDIPCONST UINT16* text,
371 INT length,
372 GDIPCONST GpFont* font,
373 GDIPCONST GpBrush* brush,
374 GDIPCONST PointF* positions,
375 INT flags,
376 GDIPCONST GpMatrix* matrix);
377 typedef GpStatus(WINGDIPAPI* FuncType_GdipCreateMatrix2)(REAL m11,
378 REAL m12,
379 REAL m21,
380 REAL m22,
381 REAL dx,
382 REAL dy,
383 GpMatrix** matrix);
384 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteMatrix)(GpMatrix* matrix);
385 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetWorldTransform)(
386 GpGraphics* graphics,
387 GpMatrix* matrix);
388 typedef GpStatus(WINGDIPAPI* FuncType_GdipResetWorldTransform)(
389 GpGraphics* graphics);
390 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteFontFamily)(
391 GpFontFamily* FontFamily);
392 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeleteFont)(GpFont* font);
393 typedef GpStatus(WINGDIPAPI* FuncType_GdipNewPrivateFontCollection)(
394 GpFontCollection** fontCollection);
395 typedef GpStatus(WINGDIPAPI* FuncType_GdipDeletePrivateFontCollection)(
396 GpFontCollection** fontCollection);
397 typedef GpStatus(WINGDIPAPI* FuncType_GdipPrivateAddMemoryFont)(
398 GpFontCollection* fontCollection,
399 GDIPCONST void* memory,
400 INT length);
401 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontCollectionFamilyList)(
402 GpFontCollection* fontCollection,
403 INT numSought,
404 GpFontFamily* gpfamilies[],
405 INT* numFound);
406 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetFontCollectionFamilyCount)(
407 GpFontCollection* fontCollection,
408 INT* numFound);
409 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetTextContrast)(GpGraphics* graphics,
410 UINT contrast);
411 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPixelOffsetMode)(
412 GpGraphics* graphics,
413 PixelOffsetMode pixelOffsetMode);
414 typedef GpStatus(WINGDIPAPI* FuncType_GdipGetImageGraphicsContext)(
415 GpImage* image,
416 GpGraphics** graphics);
417 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImageI)(GpGraphics* graphics,
418 GpImage* image,
419 INT x,
420 INT y);
421 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawImageRectI)(GpGraphics* graphics,
422 GpImage* image,
423 INT x,
424 INT y,
425 INT width,
426 INT height);
427 typedef GpStatus(WINGDIPAPI* FuncType_GdipDrawString)(
428 GpGraphics* graphics,
429 GDIPCONST WCHAR* str,
430 INT length,
431 GDIPCONST GpFont* font,
432 GDIPCONST RectF* layoutRect,
433 GDIPCONST GpStringFormat* stringFormat,
434 GDIPCONST GpBrush* brush);
435 typedef GpStatus(WINGDIPAPI* FuncType_GdipSetPenTransform)(GpPen* pen,
436 GpMatrix* matrix);
437 #define CallFunc(funcname) \
438 ((FuncType_##funcname)GdiplusExt.m_Functions[FuncId_##funcname])
439
GdiAddFontMemResourceEx(void * pFontdata,uint32_t size,void * pdv,uint32_t * num_face)440 void* CGdiplusExt::GdiAddFontMemResourceEx(void* pFontdata,
441 uint32_t size,
442 void* pdv,
443 uint32_t* num_face) {
444 if (!m_pGdiAddFontMemResourceEx)
445 return nullptr;
446
447 return m_pGdiAddFontMemResourceEx((PVOID)pFontdata, (DWORD)size, (PVOID)pdv,
448 (DWORD*)num_face);
449 }
450
GdiRemoveFontMemResourceEx(void * handle)451 bool CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) {
452 return m_pGdiRemoveFontMemResourseEx &&
453 m_pGdiRemoveFontMemResourseEx((HANDLE)handle);
454 }
455
_GdipCreateBrush(DWORD argb)456 static GpBrush* _GdipCreateBrush(DWORD argb) {
457 CGdiplusExt& GdiplusExt =
458 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
459 GpSolidFill* solidBrush = nullptr;
460 CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush);
461 return solidBrush;
462 }
463
StretchMonoToGray(int dest_width,int dest_height,const CFX_DIBitmap * pSource,FX_RECT * pClipRect)464 static std::unique_ptr<CFX_DIBitmap> StretchMonoToGray(
465 int dest_width,
466 int dest_height,
467 const CFX_DIBitmap* pSource,
468 FX_RECT* pClipRect) {
469 bool bFlipX = dest_width < 0;
470 if (bFlipX)
471 dest_width = -dest_width;
472
473 bool bFlipY = dest_height < 0;
474 if (bFlipY)
475 dest_height = -dest_height;
476
477 int result_width = pClipRect->Width();
478 int result_height = pClipRect->Height();
479 int result_pitch = (result_width + 3) / 4 * 4;
480 auto pStretched = pdfium::MakeUnique<CFX_DIBitmap>();
481 if (!pStretched->Create(result_width, result_height, FXDIB_8bppRgb))
482 return nullptr;
483
484 LPBYTE dest_buf = pStretched->GetBuffer();
485 int src_width = pSource->GetWidth();
486 int src_height = pSource->GetHeight();
487 int y_unit = src_height / dest_height;
488 int x_unit = src_width / dest_width;
489 int area_unit = y_unit * x_unit;
490 LPBYTE src_buf = pSource->GetBuffer();
491 int src_pitch = pSource->GetPitch();
492 for (int dest_y = 0; dest_y < result_height; dest_y++) {
493 LPBYTE dest_scan = dest_buf + dest_y * result_pitch;
494 int src_y_start = bFlipY ? (dest_height - 1 - dest_y - pClipRect->top)
495 : (dest_y + pClipRect->top);
496 src_y_start = src_y_start * src_height / dest_height;
497 LPBYTE src_scan = src_buf + src_y_start * src_pitch;
498 for (int dest_x = 0; dest_x < result_width; dest_x++) {
499 int sum = 0;
500 int src_x_start = bFlipX ? (dest_width - 1 - dest_x - pClipRect->left)
501 : (dest_x + pClipRect->left);
502 src_x_start = src_x_start * src_width / dest_width;
503 int src_x_end = src_x_start + x_unit;
504 LPBYTE src_line = src_scan;
505 for (int src_y = 0; src_y < y_unit; src_y++) {
506 for (int src_x = src_x_start; src_x < src_x_end; src_x++) {
507 if (!(src_line[src_x / 8] & (1 << (7 - src_x % 8)))) {
508 sum += 255;
509 }
510 }
511 src_line += src_pitch;
512 }
513 dest_scan[dest_x] = 255 - sum / area_unit;
514 }
515 }
516 return pStretched;
517 }
518
OutputImageMask(GpGraphics * pGraphics,BOOL bMonoDevice,const CFX_DIBitmap * pBitmap,int dest_left,int dest_top,int dest_width,int dest_height,FX_ARGB argb,const FX_RECT * pClipRect)519 static void OutputImageMask(GpGraphics* pGraphics,
520 BOOL bMonoDevice,
521 const CFX_DIBitmap* pBitmap,
522 int dest_left,
523 int dest_top,
524 int dest_width,
525 int dest_height,
526 FX_ARGB argb,
527 const FX_RECT* pClipRect) {
528 ASSERT(pBitmap->GetBPP() == 1);
529 CGdiplusExt& GdiplusExt =
530 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
531 int src_width = pBitmap->GetWidth(), src_height = pBitmap->GetHeight();
532 int src_pitch = pBitmap->GetPitch();
533 uint8_t* scan0 = pBitmap->GetBuffer();
534 if (src_width == 1 && src_height == 1) {
535 if ((scan0[0] & 0x80) == 0) {
536 return;
537 }
538 GpSolidFill* solidBrush;
539 CallFunc(GdipCreateSolidFill)((ARGB)argb, &solidBrush);
540 if (dest_width < 0) {
541 dest_width = -dest_width;
542 dest_left -= dest_width;
543 }
544 if (dest_height < 0) {
545 dest_height = -dest_height;
546 dest_top -= dest_height;
547 }
548 CallFunc(GdipFillRectangle)(pGraphics, solidBrush, (float)dest_left,
549 (float)dest_top, (float)dest_width,
550 (float)dest_height);
551 CallFunc(GdipDeleteBrush)(solidBrush);
552 return;
553 }
554 if (!bMonoDevice && abs(dest_width) < src_width &&
555 abs(dest_height) < src_height) {
556 FX_RECT image_rect(dest_left, dest_top, dest_left + dest_width,
557 dest_top + dest_height);
558 image_rect.Normalize();
559 FX_RECT image_clip = image_rect;
560 image_clip.Intersect(*pClipRect);
561 if (image_clip.IsEmpty()) {
562 return;
563 }
564 image_clip.Offset(-image_rect.left, -image_rect.top);
565 std::unique_ptr<CFX_DIBitmap> pStretched;
566 if (src_width * src_height > 10000) {
567 pStretched =
568 StretchMonoToGray(dest_width, dest_height, pBitmap, &image_clip);
569 } else {
570 pStretched =
571 pBitmap->StretchTo(dest_width, dest_height, false, &image_clip);
572 }
573 GpBitmap* bitmap;
574 CallFunc(GdipCreateBitmapFromScan0)(image_clip.Width(), image_clip.Height(),
575 (image_clip.Width() + 3) / 4 * 4,
576 PixelFormat8bppIndexed,
577 pStretched->GetBuffer(), &bitmap);
578 int a, r, g, b;
579 ArgbDecode(argb, a, r, g, b);
580 UINT pal[258];
581 pal[0] = 0;
582 pal[1] = 256;
583 for (int i = 0; i < 256; i++) {
584 pal[i + 2] = ArgbEncode(i * a / 255, r, g, b);
585 }
586 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal);
587 CallFunc(GdipDrawImageI)(pGraphics, bitmap,
588 image_rect.left + image_clip.left,
589 image_rect.top + image_clip.top);
590 CallFunc(GdipDisposeImage)(bitmap);
591 return;
592 }
593 GpBitmap* bitmap;
594 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
595 PixelFormat1bppIndexed, scan0, &bitmap);
596 UINT palette[4] = {PaletteFlagsHasAlpha, 2, 0, argb};
597 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)palette);
598 Point destinationPoints[] = {Point(dest_left, dest_top),
599 Point(dest_left + dest_width, dest_top),
600 Point(dest_left, dest_top + dest_height)};
601 CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3);
602 CallFunc(GdipDisposeImage)(bitmap);
603 }
OutputImage(GpGraphics * pGraphics,const CFX_DIBitmap * pBitmap,const FX_RECT * pSrcRect,int dest_left,int dest_top,int dest_width,int dest_height)604 static void OutputImage(GpGraphics* pGraphics,
605 const CFX_DIBitmap* pBitmap,
606 const FX_RECT* pSrcRect,
607 int dest_left,
608 int dest_top,
609 int dest_width,
610 int dest_height) {
611 int src_width = pSrcRect->Width(), src_height = pSrcRect->Height();
612 CGdiplusExt& GdiplusExt =
613 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
614 if (pBitmap->GetBPP() == 1 && (pSrcRect->left % 8)) {
615 FX_RECT new_rect(0, 0, src_width, src_height);
616 std::unique_ptr<CFX_DIBitmap> pCloned = pBitmap->Clone(pSrcRect);
617 if (!pCloned)
618 return;
619 OutputImage(pGraphics, pCloned.get(), &new_rect, dest_left, dest_top,
620 dest_width, dest_height);
621 return;
622 }
623 int src_pitch = pBitmap->GetPitch();
624 uint8_t* scan0 = pBitmap->GetBuffer() + pSrcRect->top * src_pitch +
625 pBitmap->GetBPP() * pSrcRect->left / 8;
626 GpBitmap* bitmap = nullptr;
627 switch (pBitmap->GetFormat()) {
628 case FXDIB_Argb:
629 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
630 PixelFormat32bppARGB, scan0, &bitmap);
631 break;
632 case FXDIB_Rgb32:
633 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
634 PixelFormat32bppRGB, scan0, &bitmap);
635 break;
636 case FXDIB_Rgb:
637 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
638 PixelFormat24bppRGB, scan0, &bitmap);
639 break;
640 case FXDIB_8bppRgb: {
641 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
642 PixelFormat8bppIndexed, scan0,
643 &bitmap);
644 UINT pal[258];
645 pal[0] = 0;
646 pal[1] = 256;
647 for (int i = 0; i < 256; i++) {
648 pal[i + 2] = pBitmap->GetPaletteEntry(i);
649 }
650 CallFunc(GdipSetImagePalette)(bitmap, (ColorPalette*)pal);
651 break;
652 }
653 case FXDIB_1bppRgb: {
654 CallFunc(GdipCreateBitmapFromScan0)(src_width, src_height, src_pitch,
655 PixelFormat1bppIndexed, scan0,
656 &bitmap);
657 break;
658 }
659 }
660 if (dest_height < 0) {
661 dest_height--;
662 }
663 if (dest_width < 0) {
664 dest_width--;
665 }
666 Point destinationPoints[] = {Point(dest_left, dest_top),
667 Point(dest_left + dest_width, dest_top),
668 Point(dest_left, dest_top + dest_height)};
669 CallFunc(GdipDrawImagePointsI)(pGraphics, bitmap, destinationPoints, 3);
670 CallFunc(GdipDisposeImage)(bitmap);
671 }
CGdiplusExt()672 CGdiplusExt::CGdiplusExt() {
673 m_hModule = nullptr;
674 m_GdiModule = nullptr;
675 for (size_t i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i++) {
676 m_Functions[i] = nullptr;
677 }
678 m_pGdiAddFontMemResourceEx = nullptr;
679 m_pGdiRemoveFontMemResourseEx = nullptr;
680 }
Load()681 void CGdiplusExt::Load() {
682 CFX_ByteString strPlusPath = "";
683 FX_CHAR buf[MAX_PATH];
684 GetSystemDirectoryA(buf, MAX_PATH);
685 strPlusPath += buf;
686 strPlusPath += "\\";
687 strPlusPath += "GDIPLUS.DLL";
688 m_hModule = LoadLibraryA(strPlusPath.c_str());
689 if (!m_hModule) {
690 return;
691 }
692 for (size_t i = 0; i < sizeof g_GdipFuncNames / sizeof(LPCSTR); i++) {
693 m_Functions[i] = GetProcAddress(m_hModule, g_GdipFuncNames[i]);
694 if (!m_Functions[i]) {
695 m_hModule = nullptr;
696 return;
697 }
698 }
699 uintptr_t gdiplusToken;
700 GdiplusStartupInput gdiplusStartupInput;
701 ((FuncType_GdiplusStartup)m_Functions[FuncId_GdiplusStartup])(
702 &gdiplusToken, &gdiplusStartupInput, nullptr);
703 m_GdiModule = LoadLibraryA("GDI32.DLL");
704 if (!m_GdiModule) {
705 return;
706 }
707 m_pGdiAddFontMemResourceEx =
708 reinterpret_cast<FuncType_GdiAddFontMemResourceEx>(
709 GetProcAddress(m_GdiModule, "AddFontMemResourceEx"));
710 m_pGdiRemoveFontMemResourseEx =
711 reinterpret_cast<FuncType_GdiRemoveFontMemResourceEx>(
712 GetProcAddress(m_GdiModule, "RemoveFontMemResourceEx"));
713 }
~CGdiplusExt()714 CGdiplusExt::~CGdiplusExt() {}
LoadMemFont(LPBYTE pData,uint32_t size)715 LPVOID CGdiplusExt::LoadMemFont(LPBYTE pData, uint32_t size) {
716 GpFontCollection* pCollection = nullptr;
717 CGdiplusExt& GdiplusExt =
718 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
719 CallFunc(GdipNewPrivateFontCollection)(&pCollection);
720 GpStatus status =
721 CallFunc(GdipPrivateAddMemoryFont)(pCollection, pData, size);
722 if (status == Ok) {
723 return pCollection;
724 }
725 CallFunc(GdipDeletePrivateFontCollection)(&pCollection);
726 return nullptr;
727 }
DeleteMemFont(LPVOID pCollection)728 void CGdiplusExt::DeleteMemFont(LPVOID pCollection) {
729 CGdiplusExt& GdiplusExt =
730 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
731 CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection);
732 }
GdipCreateBitmap(CFX_DIBitmap * pBitmap,void ** bitmap)733 bool CGdiplusExt::GdipCreateBitmap(CFX_DIBitmap* pBitmap, void** bitmap) {
734 CGdiplusExt& GdiplusExt =
735 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
736 PixelFormat format;
737 switch (pBitmap->GetFormat()) {
738 case FXDIB_Rgb:
739 format = PixelFormat24bppRGB;
740 break;
741 case FXDIB_Rgb32:
742 format = PixelFormat32bppRGB;
743 break;
744 case FXDIB_Argb:
745 format = PixelFormat32bppARGB;
746 break;
747 default:
748 return false;
749 }
750 GpStatus status = CallFunc(GdipCreateBitmapFromScan0)(
751 pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap->GetPitch(), format,
752 pBitmap->GetBuffer(), (GpBitmap**)bitmap);
753 if (status == Ok) {
754 return true;
755 }
756 return false;
757 }
GdipCreateFromImage(void * bitmap,void ** graphics)758 bool CGdiplusExt::GdipCreateFromImage(void* bitmap, void** graphics) {
759 CGdiplusExt& GdiplusExt =
760 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
761 GpStatus status = CallFunc(GdipGetImageGraphicsContext)(
762 (GpBitmap*)bitmap, (GpGraphics**)graphics);
763 if (status == Ok) {
764 return true;
765 }
766 return false;
767 }
GdipCreateFontFamilyFromName(const FX_WCHAR * name,void * pFontCollection,void ** pFamily)768 bool CGdiplusExt::GdipCreateFontFamilyFromName(const FX_WCHAR* name,
769 void* pFontCollection,
770 void** pFamily) {
771 CGdiplusExt& GdiplusExt =
772 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
773 GpStatus status = CallFunc(GdipCreateFontFamilyFromName)(
774 (GDIPCONST WCHAR*)name, (GpFontCollection*)pFontCollection,
775 (GpFontFamily**)pFamily);
776 if (status == Ok) {
777 return true;
778 }
779 return false;
780 }
GdipCreateFontFromFamily(void * pFamily,FX_FLOAT font_size,int fontstyle,int flag,void ** pFont)781 bool CGdiplusExt::GdipCreateFontFromFamily(void* pFamily,
782 FX_FLOAT font_size,
783 int fontstyle,
784 int flag,
785 void** pFont) {
786 CGdiplusExt& GdiplusExt =
787 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
788 GpStatus status =
789 CallFunc(GdipCreateFont)((GpFontFamily*)pFamily, font_size, fontstyle,
790 Unit(flag), (GpFont**)pFont);
791 if (status == Ok) {
792 return true;
793 }
794 return false;
795 }
GdipGetFontSize(void * pFont,FX_FLOAT * size)796 void CGdiplusExt::GdipGetFontSize(void* pFont, FX_FLOAT* size) {
797 REAL get_size;
798 CGdiplusExt& GdiplusExt =
799 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
800 GpStatus status = CallFunc(GdipGetFontSize)((GpFont*)pFont, (REAL*)&get_size);
801 if (status == Ok) {
802 *size = (FX_FLOAT)get_size;
803 } else {
804 *size = 0;
805 }
806 }
GdipSetTextRenderingHint(void * graphics,int mode)807 void CGdiplusExt::GdipSetTextRenderingHint(void* graphics, int mode) {
808 CGdiplusExt& GdiplusExt =
809 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
810 CallFunc(GdipSetTextRenderingHint)((GpGraphics*)graphics,
811 (TextRenderingHint)mode);
812 }
GdipSetPageUnit(void * graphics,uint32_t unit)813 void CGdiplusExt::GdipSetPageUnit(void* graphics, uint32_t unit) {
814 CGdiplusExt& GdiplusExt =
815 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
816 CallFunc(GdipSetPageUnit)((GpGraphics*)graphics, (GpUnit)unit);
817 }
GdipDrawDriverString(void * graphics,unsigned short * text,int length,void * font,void * brush,void * positions,int flags,const void * matrix)818 bool CGdiplusExt::GdipDrawDriverString(void* graphics,
819 unsigned short* text,
820 int length,
821 void* font,
822 void* brush,
823 void* positions,
824 int flags,
825 const void* matrix) {
826 CGdiplusExt& GdiplusExt =
827 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
828 GpStatus status = CallFunc(GdipDrawDriverString)(
829 (GpGraphics*)graphics, (GDIPCONST UINT16*)text, (INT)length,
830 (GDIPCONST GpFont*)font, (GDIPCONST GpBrush*)brush,
831 (GDIPCONST PointF*)positions, (INT)flags, (GDIPCONST GpMatrix*)matrix);
832 if (status == Ok) {
833 return true;
834 }
835 return false;
836 }
GdipCreateBrush(uint32_t fill_argb,void ** pBrush)837 void CGdiplusExt::GdipCreateBrush(uint32_t fill_argb, void** pBrush) {
838 CGdiplusExt& GdiplusExt =
839 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
840 CallFunc(GdipCreateSolidFill)((ARGB)fill_argb, (GpSolidFill**)pBrush);
841 }
GdipDeleteBrush(void * pBrush)842 void CGdiplusExt::GdipDeleteBrush(void* pBrush) {
843 CGdiplusExt& GdiplusExt =
844 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
845 CallFunc(GdipDeleteBrush)((GpSolidFill*)pBrush);
846 }
GdipCreateFontFromCollection(void * pFontCollection,FX_FLOAT font_size,int fontstyle)847 void* CGdiplusExt::GdipCreateFontFromCollection(void* pFontCollection,
848 FX_FLOAT font_size,
849 int fontstyle) {
850 CGdiplusExt& GdiplusExt =
851 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
852 int numFamilies = 0;
853 GpStatus status = CallFunc(GdipGetFontCollectionFamilyCount)(
854 (GpFontCollection*)pFontCollection, &numFamilies);
855 if (status != Ok) {
856 return nullptr;
857 }
858 GpFontFamily* family_list[1];
859 status = CallFunc(GdipGetFontCollectionFamilyList)(
860 (GpFontCollection*)pFontCollection, 1, family_list, &numFamilies);
861 if (status != Ok) {
862 return nullptr;
863 }
864 GpFont* pFont = nullptr;
865 status = CallFunc(GdipCreateFont)(family_list[0], font_size, fontstyle,
866 UnitPixel, &pFont);
867 if (status != Ok) {
868 return nullptr;
869 }
870 return pFont;
871 }
GdipCreateMatrix(FX_FLOAT a,FX_FLOAT b,FX_FLOAT c,FX_FLOAT d,FX_FLOAT e,FX_FLOAT f,void ** matrix)872 void CGdiplusExt::GdipCreateMatrix(FX_FLOAT a,
873 FX_FLOAT b,
874 FX_FLOAT c,
875 FX_FLOAT d,
876 FX_FLOAT e,
877 FX_FLOAT f,
878 void** matrix) {
879 CGdiplusExt& GdiplusExt =
880 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
881 CallFunc(GdipCreateMatrix2)(a, b, c, d, e, f, (GpMatrix**)matrix);
882 }
GdipDeleteMatrix(void * matrix)883 void CGdiplusExt::GdipDeleteMatrix(void* matrix) {
884 CGdiplusExt& GdiplusExt =
885 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
886 CallFunc(GdipDeleteMatrix)((GpMatrix*)matrix);
887 }
GdipDeleteFontFamily(void * pFamily)888 void CGdiplusExt::GdipDeleteFontFamily(void* pFamily) {
889 CGdiplusExt& GdiplusExt =
890 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
891 CallFunc(GdipDeleteFontFamily)((GpFontFamily*)pFamily);
892 }
GdipDeleteFont(void * pFont)893 void CGdiplusExt::GdipDeleteFont(void* pFont) {
894 CGdiplusExt& GdiplusExt =
895 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
896 CallFunc(GdipDeleteFont)((GpFont*)pFont);
897 }
GdipSetWorldTransform(void * graphics,void * pMatrix)898 void CGdiplusExt::GdipSetWorldTransform(void* graphics, void* pMatrix) {
899 CGdiplusExt& GdiplusExt =
900 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
901 CallFunc(GdipSetWorldTransform)((GpGraphics*)graphics, (GpMatrix*)pMatrix);
902 }
GdipDisposeImage(void * bitmap)903 void CGdiplusExt::GdipDisposeImage(void* bitmap) {
904 CGdiplusExt& GdiplusExt =
905 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
906 CallFunc(GdipDisposeImage)((GpBitmap*)bitmap);
907 }
GdipDeleteGraphics(void * graphics)908 void CGdiplusExt::GdipDeleteGraphics(void* graphics) {
909 CGdiplusExt& GdiplusExt =
910 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
911 CallFunc(GdipDeleteGraphics)((GpGraphics*)graphics);
912 }
StretchBitMask(HDC hDC,BOOL bMonoDevice,const CFX_DIBitmap * pBitmap,int dest_left,int dest_top,int dest_width,int dest_height,uint32_t argb,const FX_RECT * pClipRect,int flags)913 bool CGdiplusExt::StretchBitMask(HDC hDC,
914 BOOL bMonoDevice,
915 const CFX_DIBitmap* pBitmap,
916 int dest_left,
917 int dest_top,
918 int dest_width,
919 int dest_height,
920 uint32_t argb,
921 const FX_RECT* pClipRect,
922 int flags) {
923 ASSERT(pBitmap->GetBPP() == 1);
924 CGdiplusExt& GdiplusExt =
925 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
926 GpGraphics* pGraphics = nullptr;
927 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics);
928 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel);
929 if (flags & FXDIB_NOSMOOTH) {
930 CallFunc(GdipSetInterpolationMode)(pGraphics,
931 InterpolationModeNearestNeighbor);
932 } else {
933 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality);
934 }
935 OutputImageMask(pGraphics, bMonoDevice, pBitmap, dest_left, dest_top,
936 dest_width, dest_height, argb, pClipRect);
937 CallFunc(GdipDeleteGraphics)(pGraphics);
938 return true;
939 }
StretchDIBits(HDC hDC,const CFX_DIBitmap * pBitmap,int dest_left,int dest_top,int dest_width,int dest_height,const FX_RECT * pClipRect,int flags)940 bool CGdiplusExt::StretchDIBits(HDC hDC,
941 const CFX_DIBitmap* pBitmap,
942 int dest_left,
943 int dest_top,
944 int dest_width,
945 int dest_height,
946 const FX_RECT* pClipRect,
947 int flags) {
948 GpGraphics* pGraphics;
949 CGdiplusExt& GdiplusExt =
950 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
951 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics);
952 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel);
953 if (flags & FXDIB_NOSMOOTH) {
954 CallFunc(GdipSetInterpolationMode)(pGraphics,
955 InterpolationModeNearestNeighbor);
956 } else if (pBitmap->GetWidth() > abs(dest_width) / 2 ||
957 pBitmap->GetHeight() > abs(dest_height) / 2) {
958 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeHighQuality);
959 } else {
960 CallFunc(GdipSetInterpolationMode)(pGraphics, InterpolationModeBilinear);
961 }
962 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
963 OutputImage(pGraphics, pBitmap, &src_rect, dest_left, dest_top, dest_width,
964 dest_height);
965 CallFunc(GdipDeleteGraphics)(pGraphics);
966 CallFunc(GdipDeleteGraphics)(pGraphics);
967 return true;
968 }
_GdipCreatePen(const CFX_GraphStateData * pGraphState,const CFX_Matrix * pMatrix,DWORD argb,bool bTextMode=false)969 static GpPen* _GdipCreatePen(const CFX_GraphStateData* pGraphState,
970 const CFX_Matrix* pMatrix,
971 DWORD argb,
972 bool bTextMode = false) {
973 CGdiplusExt& GdiplusExt =
974 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
975 FX_FLOAT width = pGraphState ? pGraphState->m_LineWidth : 1.0f;
976 if (!bTextMode) {
977 FX_FLOAT unit =
978 pMatrix ? 1.0f / ((pMatrix->GetXUnit() + pMatrix->GetYUnit()) / 2)
979 : 1.0f;
980 if (width < unit) {
981 width = unit;
982 }
983 }
984 GpPen* pPen = nullptr;
985 CallFunc(GdipCreatePen1)((ARGB)argb, width, UnitWorld, &pPen);
986 LineCap lineCap = LineCapFlat;
987 DashCap dashCap = DashCapFlat;
988 bool bDashExtend = false;
989 switch (pGraphState->m_LineCap) {
990 case CFX_GraphStateData::LineCapButt:
991 lineCap = LineCapFlat;
992 break;
993 case CFX_GraphStateData::LineCapRound:
994 lineCap = LineCapRound;
995 dashCap = DashCapRound;
996 bDashExtend = true;
997 break;
998 case CFX_GraphStateData::LineCapSquare:
999 lineCap = LineCapSquare;
1000 bDashExtend = true;
1001 break;
1002 }
1003 CallFunc(GdipSetPenLineCap197819)(pPen, lineCap, lineCap, dashCap);
1004 LineJoin lineJoin = LineJoinMiterClipped;
1005 switch (pGraphState->m_LineJoin) {
1006 case CFX_GraphStateData::LineJoinMiter:
1007 lineJoin = LineJoinMiterClipped;
1008 break;
1009 case CFX_GraphStateData::LineJoinRound:
1010 lineJoin = LineJoinRound;
1011 break;
1012 case CFX_GraphStateData::LineJoinBevel:
1013 lineJoin = LineJoinBevel;
1014 break;
1015 }
1016 CallFunc(GdipSetPenLineJoin)(pPen, lineJoin);
1017 if (pGraphState->m_DashCount) {
1018 FX_FLOAT* pDashArray = FX_Alloc(
1019 FX_FLOAT, pGraphState->m_DashCount + pGraphState->m_DashCount % 2);
1020 int nCount = 0;
1021 FX_FLOAT on_leftover = 0, off_leftover = 0;
1022 for (int i = 0; i < pGraphState->m_DashCount; i += 2) {
1023 FX_FLOAT on_phase = pGraphState->m_DashArray[i];
1024 FX_FLOAT off_phase;
1025 if (i == pGraphState->m_DashCount - 1) {
1026 off_phase = on_phase;
1027 } else {
1028 off_phase = pGraphState->m_DashArray[i + 1];
1029 }
1030 on_phase /= width;
1031 off_phase /= width;
1032 if (on_phase + off_phase <= 0.00002f) {
1033 on_phase = 1.0f / 10;
1034 off_phase = 1.0f / 10;
1035 }
1036 if (bDashExtend) {
1037 if (off_phase < 1) {
1038 off_phase = 0;
1039 } else {
1040 off_phase -= 1;
1041 }
1042 on_phase += 1;
1043 }
1044 if (on_phase == 0 || off_phase == 0) {
1045 if (nCount == 0) {
1046 on_leftover += on_phase;
1047 off_leftover += off_phase;
1048 } else {
1049 pDashArray[nCount - 2] += on_phase;
1050 pDashArray[nCount - 1] += off_phase;
1051 }
1052 } else {
1053 pDashArray[nCount++] = on_phase + on_leftover;
1054 on_leftover = 0;
1055 pDashArray[nCount++] = off_phase + off_leftover;
1056 off_leftover = 0;
1057 }
1058 }
1059 CallFunc(GdipSetPenDashArray)(pPen, pDashArray, nCount);
1060 FX_FLOAT phase = pGraphState->m_DashPhase;
1061 if (bDashExtend) {
1062 if (phase < 0.5f) {
1063 phase = 0;
1064 } else {
1065 phase -= 0.5f;
1066 }
1067 }
1068 CallFunc(GdipSetPenDashOffset)(pPen, phase);
1069 FX_Free(pDashArray);
1070 pDashArray = nullptr;
1071 }
1072 CallFunc(GdipSetPenMiterLimit)(pPen, pGraphState->m_MiterLimit);
1073 return pPen;
1074 }
IsSmallTriangle(PointF * points,const CFX_Matrix * pMatrix,int & v1,int & v2)1075 static bool IsSmallTriangle(PointF* points,
1076 const CFX_Matrix* pMatrix,
1077 int& v1,
1078 int& v2) {
1079 int pairs[] = {1, 2, 0, 2, 0, 1};
1080 for (int i = 0; i < 3; i++) {
1081 int pair1 = pairs[i * 2];
1082 int pair2 = pairs[i * 2 + 1];
1083
1084 CFX_PointF p1(points[pair1].X, points[pair1].Y);
1085 CFX_PointF p2(points[pair2].X, points[pair2].Y);
1086 if (pMatrix) {
1087 p1 = pMatrix->Transform(p1);
1088 p2 = pMatrix->Transform(p2);
1089 }
1090
1091 CFX_PointF diff = p1 - p2;
1092 FX_FLOAT distance_square = (diff.x * diff.x) + (diff.y * diff.y);
1093 if (distance_square < (1.0f * 2 + 1.0f / 4)) {
1094 v1 = i;
1095 v2 = pair1;
1096 return true;
1097 }
1098 }
1099 return false;
1100 }
DrawPath(HDC hDC,const CFX_PathData * pPathData,const CFX_Matrix * pObject2Device,const CFX_GraphStateData * pGraphState,uint32_t fill_argb,uint32_t stroke_argb,int fill_mode)1101 bool CGdiplusExt::DrawPath(HDC hDC,
1102 const CFX_PathData* pPathData,
1103 const CFX_Matrix* pObject2Device,
1104 const CFX_GraphStateData* pGraphState,
1105 uint32_t fill_argb,
1106 uint32_t stroke_argb,
1107 int fill_mode) {
1108 auto& pPoints = pPathData->GetPoints();
1109 if (pPoints.empty())
1110 return true;
1111
1112 GpGraphics* pGraphics = nullptr;
1113 CGdiplusExt& GdiplusExt =
1114 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
1115 CallFunc(GdipCreateFromHDC)(hDC, &pGraphics);
1116 CallFunc(GdipSetPageUnit)(pGraphics, UnitPixel);
1117 CallFunc(GdipSetPixelOffsetMode)(pGraphics, PixelOffsetModeHalf);
1118 GpMatrix* pMatrix = nullptr;
1119 if (pObject2Device) {
1120 CallFunc(GdipCreateMatrix2)(pObject2Device->a, pObject2Device->b,
1121 pObject2Device->c, pObject2Device->d,
1122 pObject2Device->e, pObject2Device->f, &pMatrix);
1123 CallFunc(GdipSetWorldTransform)(pGraphics, pMatrix);
1124 }
1125 PointF* points = FX_Alloc(PointF, pPoints.size());
1126 BYTE* types = FX_Alloc(BYTE, pPoints.size());
1127 int nSubPathes = 0;
1128 bool bSubClose = false;
1129 int pos_subclose = 0;
1130 bool bSmooth = false;
1131 int startpoint = 0;
1132 for (size_t i = 0; i < pPoints.size(); i++) {
1133 points[i].X = pPoints[i].m_Point.x;
1134 points[i].Y = pPoints[i].m_Point.y;
1135
1136 CFX_PointF pos = pPoints[i].m_Point;
1137 if (pObject2Device)
1138 pos = pObject2Device->Transform(pos);
1139
1140 if (pos.x > 50000 * 1.0f)
1141 points[i].X = 50000 * 1.0f;
1142 if (pos.x < -50000 * 1.0f)
1143 points[i].X = -50000 * 1.0f;
1144 if (pos.y > 50000 * 1.0f)
1145 points[i].Y = 50000 * 1.0f;
1146 if (pos.y < -50000 * 1.0f)
1147 points[i].Y = -50000 * 1.0f;
1148
1149 FXPT_TYPE point_type = pPoints[i].m_Type;
1150 if (point_type == FXPT_TYPE::MoveTo) {
1151 types[i] = PathPointTypeStart;
1152 nSubPathes++;
1153 bSubClose = false;
1154 startpoint = i;
1155 } else if (point_type == FXPT_TYPE::LineTo) {
1156 types[i] = PathPointTypeLine;
1157 if (pPoints[i - 1].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
1158 (i == pPoints.size() - 1 ||
1159 pPoints[i + 1].IsTypeAndOpen(FXPT_TYPE::MoveTo)) &&
1160 points[i].Y == points[i - 1].Y && points[i].X == points[i - 1].X) {
1161 points[i].X += 0.01f;
1162 continue;
1163 }
1164 if (!bSmooth && points[i].X != points[i - 1].X &&
1165 points[i].Y != points[i - 1].Y) {
1166 bSmooth = true;
1167 }
1168 } else if (point_type == FXPT_TYPE::BezierTo) {
1169 types[i] = PathPointTypeBezier;
1170 bSmooth = true;
1171 }
1172 if (pPoints[i].m_CloseFigure) {
1173 if (bSubClose) {
1174 types[pos_subclose] &= ~PathPointTypeCloseSubpath;
1175 } else {
1176 bSubClose = true;
1177 }
1178 pos_subclose = i;
1179 types[i] |= PathPointTypeCloseSubpath;
1180 if (!bSmooth && points[i].X != points[startpoint].X &&
1181 points[i].Y != points[startpoint].Y) {
1182 bSmooth = true;
1183 }
1184 }
1185 }
1186 if (fill_mode & FXFILL_NOPATHSMOOTH) {
1187 bSmooth = false;
1188 CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeNone);
1189 } else if (!(fill_mode & FXFILL_FULLCOVER)) {
1190 if (!bSmooth && (fill_mode & 3)) {
1191 bSmooth = true;
1192 }
1193 if (bSmooth || (pGraphState && pGraphState->m_LineWidth > 2)) {
1194 CallFunc(GdipSetSmoothingMode)(pGraphics, SmoothingModeAntiAlias);
1195 }
1196 }
1197 int new_fill_mode = fill_mode & 3;
1198 if (pPoints.size() == 4 && !pGraphState) {
1199 int v1, v2;
1200 if (IsSmallTriangle(points, pObject2Device, v1, v2)) {
1201 GpPen* pPen = nullptr;
1202 CallFunc(GdipCreatePen1)(fill_argb, 1.0f, UnitPixel, &pPen);
1203 CallFunc(GdipDrawLineI)(
1204 pGraphics, pPen, FXSYS_round(points[v1].X), FXSYS_round(points[v1].Y),
1205 FXSYS_round(points[v2].X), FXSYS_round(points[v2].Y));
1206 CallFunc(GdipDeletePen)(pPen);
1207 return true;
1208 }
1209 }
1210 GpPath* pGpPath = nullptr;
1211 CallFunc(GdipCreatePath2)(points, types, pPoints.size(),
1212 GdiFillType2Gdip(new_fill_mode), &pGpPath);
1213 if (!pGpPath) {
1214 if (pMatrix)
1215 CallFunc(GdipDeleteMatrix)(pMatrix);
1216
1217 FX_Free(points);
1218 FX_Free(types);
1219 CallFunc(GdipDeleteGraphics)(pGraphics);
1220 return false;
1221 }
1222 if (new_fill_mode) {
1223 GpBrush* pBrush = _GdipCreateBrush(fill_argb);
1224 CallFunc(GdipSetPathFillMode)(pGpPath, GdiFillType2Gdip(new_fill_mode));
1225 CallFunc(GdipFillPath)(pGraphics, pBrush, pGpPath);
1226 CallFunc(GdipDeleteBrush)(pBrush);
1227 }
1228 if (pGraphState && stroke_argb) {
1229 GpPen* pPen = _GdipCreatePen(pGraphState, pObject2Device, stroke_argb,
1230 !!(fill_mode & FX_STROKE_TEXT_MODE));
1231 if (nSubPathes == 1) {
1232 CallFunc(GdipDrawPath)(pGraphics, pPen, pGpPath);
1233 } else {
1234 int iStart = 0;
1235 for (size_t i = 0; i < pPoints.size(); i++) {
1236 if (i == pPoints.size() - 1 || types[i + 1] == PathPointTypeStart) {
1237 GpPath* pSubPath;
1238 CallFunc(GdipCreatePath2)(points + iStart, types + iStart,
1239 i - iStart + 1,
1240 GdiFillType2Gdip(new_fill_mode), &pSubPath);
1241 iStart = i + 1;
1242 CallFunc(GdipDrawPath)(pGraphics, pPen, pSubPath);
1243 CallFunc(GdipDeletePath)(pSubPath);
1244 }
1245 }
1246 }
1247 CallFunc(GdipDeletePen)(pPen);
1248 }
1249 if (pMatrix) {
1250 CallFunc(GdipDeleteMatrix)(pMatrix);
1251 }
1252 FX_Free(points);
1253 FX_Free(types);
1254 CallFunc(GdipDeletePath)(pGpPath);
1255 CallFunc(GdipDeleteGraphics)(pGraphics);
1256 return true;
1257 }
1258
1259 class GpStream final : public IStream {
1260 public:
GpStream()1261 GpStream() : m_RefCount(1), m_ReadPos(0) {}
1262
1263 // IUnknown
QueryInterface(REFIID iid,void ** ppvObject)1264 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
1265 void** ppvObject) override {
1266 if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) ||
1267 iid == __uuidof(ISequentialStream)) {
1268 *ppvObject = static_cast<IStream*>(this);
1269 AddRef();
1270 return S_OK;
1271 }
1272 return E_NOINTERFACE;
1273 }
AddRef()1274 ULONG STDMETHODCALLTYPE AddRef() override {
1275 return (ULONG)InterlockedIncrement(&m_RefCount);
1276 }
Release()1277 ULONG STDMETHODCALLTYPE Release() override {
1278 ULONG res = (ULONG)InterlockedDecrement(&m_RefCount);
1279 if (res == 0) {
1280 delete this;
1281 }
1282 return res;
1283 }
1284
1285 // ISequentialStream
Read(void * Output,ULONG cb,ULONG * pcbRead)1286 HRESULT STDMETHODCALLTYPE Read(void* Output,
1287 ULONG cb,
1288 ULONG* pcbRead) override {
1289 size_t bytes_left;
1290 size_t bytes_out;
1291 if (pcbRead) {
1292 *pcbRead = 0;
1293 }
1294 if (m_ReadPos == m_InterStream.GetLength()) {
1295 return HRESULT_FROM_WIN32(ERROR_END_OF_MEDIA);
1296 }
1297 bytes_left = m_InterStream.GetLength() - m_ReadPos;
1298 bytes_out = std::min(pdfium::base::checked_cast<size_t>(cb), bytes_left);
1299 FXSYS_memcpy(Output, m_InterStream.GetBuffer() + m_ReadPos, bytes_out);
1300 m_ReadPos += (int32_t)bytes_out;
1301 if (pcbRead) {
1302 *pcbRead = (ULONG)bytes_out;
1303 }
1304 return S_OK;
1305 }
Write(void const * Input,ULONG cb,ULONG * pcbWritten)1306 HRESULT STDMETHODCALLTYPE Write(void const* Input,
1307 ULONG cb,
1308 ULONG* pcbWritten) override {
1309 if (cb <= 0) {
1310 if (pcbWritten) {
1311 *pcbWritten = 0;
1312 }
1313 return S_OK;
1314 }
1315 m_InterStream.InsertBlock(m_InterStream.GetLength(), Input, cb);
1316 if (pcbWritten) {
1317 *pcbWritten = cb;
1318 }
1319 return S_OK;
1320 }
1321
1322 // IStream
SetSize(ULARGE_INTEGER)1323 HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) override {
1324 return E_NOTIMPL;
1325 }
CopyTo(IStream *,ULARGE_INTEGER,ULARGE_INTEGER *,ULARGE_INTEGER *)1326 HRESULT STDMETHODCALLTYPE CopyTo(IStream*,
1327 ULARGE_INTEGER,
1328 ULARGE_INTEGER*,
1329 ULARGE_INTEGER*) override {
1330 return E_NOTIMPL;
1331 }
Commit(DWORD)1332 HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
Revert()1333 HRESULT STDMETHODCALLTYPE Revert() override { return E_NOTIMPL; }
LockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD)1334 HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
1335 ULARGE_INTEGER,
1336 DWORD) override {
1337 return E_NOTIMPL;
1338 }
UnlockRegion(ULARGE_INTEGER,ULARGE_INTEGER,DWORD)1339 HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
1340 ULARGE_INTEGER,
1341 DWORD) override {
1342 return E_NOTIMPL;
1343 }
Clone(IStream ** stream)1344 HRESULT STDMETHODCALLTYPE Clone(IStream** stream) override {
1345 return E_NOTIMPL;
1346 }
Seek(LARGE_INTEGER liDistanceToMove,DWORD dwOrigin,ULARGE_INTEGER * lpNewFilePointer)1347 HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove,
1348 DWORD dwOrigin,
1349 ULARGE_INTEGER* lpNewFilePointer) override {
1350 long start = 0;
1351 long new_read_position;
1352 switch (dwOrigin) {
1353 case STREAM_SEEK_SET:
1354 start = 0;
1355 break;
1356 case STREAM_SEEK_CUR:
1357 start = m_ReadPos;
1358 break;
1359 case STREAM_SEEK_END:
1360 start = m_InterStream.GetLength();
1361 break;
1362 default:
1363 return STG_E_INVALIDFUNCTION;
1364 break;
1365 }
1366 new_read_position = start + (long)liDistanceToMove.QuadPart;
1367 if (new_read_position < 0 ||
1368 new_read_position > m_InterStream.GetLength()) {
1369 return STG_E_SEEKERROR;
1370 }
1371 m_ReadPos = new_read_position;
1372 if (lpNewFilePointer) {
1373 lpNewFilePointer->QuadPart = m_ReadPos;
1374 }
1375 return S_OK;
1376 }
Stat(STATSTG * pStatstg,DWORD grfStatFlag)1377 HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg,
1378 DWORD grfStatFlag) override {
1379 if (!pStatstg) {
1380 return STG_E_INVALIDFUNCTION;
1381 }
1382 ZeroMemory(pStatstg, sizeof(STATSTG));
1383 pStatstg->cbSize.QuadPart = m_InterStream.GetLength();
1384 return S_OK;
1385 }
1386
1387 private:
1388 LONG m_RefCount;
1389 int m_ReadPos;
1390 CFX_ByteTextBuf m_InterStream;
1391 };
1392
1393 typedef struct {
1394 BITMAPINFO* pbmi;
1395 int Stride;
1396 LPBYTE pScan0;
1397 GpBitmap* pBitmap;
1398 BitmapData* pBitmapData;
1399 GpStream* pStream;
1400 } PREVIEW3_DIBITMAP;
1401
LoadDIBitmap(WINDIB_Open_Args_ args)1402 static PREVIEW3_DIBITMAP* LoadDIBitmap(WINDIB_Open_Args_ args) {
1403 GpBitmap* pBitmap;
1404 GpStream* pStream = nullptr;
1405 CGdiplusExt& GdiplusExt =
1406 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
1407 Status status = Ok;
1408 if (args.flags == WINDIB_OPEN_PATHNAME) {
1409 status = CallFunc(GdipCreateBitmapFromFileICM)((wchar_t*)args.path_name,
1410 &pBitmap);
1411 } else {
1412 if (args.memory_size == 0 || !args.memory_base) {
1413 return nullptr;
1414 }
1415 pStream = new GpStream;
1416 pStream->Write(args.memory_base, (ULONG)args.memory_size, nullptr);
1417 status = CallFunc(GdipCreateBitmapFromStreamICM)(pStream, &pBitmap);
1418 }
1419 if (status != Ok) {
1420 if (pStream) {
1421 pStream->Release();
1422 }
1423 return nullptr;
1424 }
1425 UINT height, width;
1426 CallFunc(GdipGetImageHeight)(pBitmap, &height);
1427 CallFunc(GdipGetImageWidth)(pBitmap, &width);
1428 PixelFormat pixel_format;
1429 CallFunc(GdipGetImagePixelFormat)(pBitmap, &pixel_format);
1430 int info_size = sizeof(BITMAPINFOHEADER);
1431 int bpp = 24;
1432 int dest_pixel_format = PixelFormat24bppRGB;
1433 if (pixel_format == PixelFormat1bppIndexed) {
1434 info_size += 8;
1435 bpp = 1;
1436 dest_pixel_format = PixelFormat1bppIndexed;
1437 } else if (pixel_format == PixelFormat8bppIndexed) {
1438 info_size += 1024;
1439 bpp = 8;
1440 dest_pixel_format = PixelFormat8bppIndexed;
1441 } else if (pixel_format == PixelFormat32bppARGB) {
1442 bpp = 32;
1443 dest_pixel_format = PixelFormat32bppARGB;
1444 }
1445 LPBYTE buf = FX_Alloc(BYTE, info_size);
1446 BITMAPINFOHEADER* pbmih = (BITMAPINFOHEADER*)buf;
1447 pbmih->biBitCount = bpp;
1448 pbmih->biCompression = BI_RGB;
1449 pbmih->biHeight = -(int)height;
1450 pbmih->biPlanes = 1;
1451 pbmih->biWidth = width;
1452 Rect rect(0, 0, width, height);
1453 BitmapData* pBitmapData = FX_Alloc(BitmapData, 1);
1454 CallFunc(GdipBitmapLockBits)(pBitmap, &rect, ImageLockModeRead,
1455 dest_pixel_format, pBitmapData);
1456 if (pixel_format == PixelFormat1bppIndexed ||
1457 pixel_format == PixelFormat8bppIndexed) {
1458 DWORD* ppal = (DWORD*)(buf + sizeof(BITMAPINFOHEADER));
1459 struct {
1460 UINT flags;
1461 UINT Count;
1462 DWORD Entries[256];
1463 } pal;
1464 int size = 0;
1465 CallFunc(GdipGetImagePaletteSize)(pBitmap, &size);
1466 CallFunc(GdipGetImagePalette)(pBitmap, (ColorPalette*)&pal, size);
1467 int entries = pixel_format == PixelFormat1bppIndexed ? 2 : 256;
1468 for (int i = 0; i < entries; i++) {
1469 ppal[i] = pal.Entries[i] & 0x00ffffff;
1470 }
1471 }
1472 PREVIEW3_DIBITMAP* pInfo = FX_Alloc(PREVIEW3_DIBITMAP, 1);
1473 pInfo->pbmi = (BITMAPINFO*)buf;
1474 pInfo->pScan0 = (LPBYTE)pBitmapData->Scan0;
1475 pInfo->Stride = pBitmapData->Stride;
1476 pInfo->pBitmap = pBitmap;
1477 pInfo->pBitmapData = pBitmapData;
1478 pInfo->pStream = pStream;
1479 return pInfo;
1480 }
1481
FreeDIBitmap(PREVIEW3_DIBITMAP * pInfo)1482 static void FreeDIBitmap(PREVIEW3_DIBITMAP* pInfo) {
1483 CGdiplusExt& GdiplusExt =
1484 ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
1485 CallFunc(GdipBitmapUnlockBits)(pInfo->pBitmap, pInfo->pBitmapData);
1486 CallFunc(GdipDisposeImage)(pInfo->pBitmap);
1487 FX_Free(pInfo->pBitmapData);
1488 FX_Free((LPBYTE)pInfo->pbmi);
1489 if (pInfo->pStream) {
1490 pInfo->pStream->Release();
1491 }
1492 FX_Free(pInfo);
1493 }
1494
1495 CFX_DIBitmap* _FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi,
1496 LPVOID pData,
1497 bool bAlpha);
LoadDIBitmap(WINDIB_Open_Args_ args)1498 CFX_DIBitmap* CGdiplusExt::LoadDIBitmap(WINDIB_Open_Args_ args) {
1499 PREVIEW3_DIBITMAP* pInfo = ::LoadDIBitmap(args);
1500 if (!pInfo) {
1501 return nullptr;
1502 }
1503 int height = abs(pInfo->pbmi->bmiHeader.biHeight);
1504 int width = pInfo->pbmi->bmiHeader.biWidth;
1505 int dest_pitch = (width * pInfo->pbmi->bmiHeader.biBitCount + 31) / 32 * 4;
1506 LPBYTE pData = FX_Alloc2D(BYTE, dest_pitch, height);
1507 if (dest_pitch == pInfo->Stride) {
1508 FXSYS_memcpy(pData, pInfo->pScan0, dest_pitch * height);
1509 } else {
1510 for (int i = 0; i < height; i++) {
1511 FXSYS_memcpy(pData + dest_pitch * i, pInfo->pScan0 + pInfo->Stride * i,
1512 dest_pitch);
1513 }
1514 }
1515 CFX_DIBitmap* pDIBitmap = _FX_WindowsDIB_LoadFromBuf(
1516 pInfo->pbmi, pData, pInfo->pbmi->bmiHeader.biBitCount == 32);
1517 FX_Free(pData);
1518 FreeDIBitmap(pInfo);
1519 return pDIBitmap;
1520 }
1521