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