Home | History | Annotate | Download | only in win32
      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 
    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 
    514 bool CGdiplusExt::GdiRemoveFontMemResourceEx(void* handle) {
    515   return m_pGdiRemoveFontMemResourseEx &&
    516          m_pGdiRemoveFontMemResourseEx((HANDLE)handle);
    517 }
    518 
    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 
    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 
    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 }
    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 
    740 CGdiplusExt::CGdiplusExt() {}
    741 
    742 CGdiplusExt::~CGdiplusExt() {
    743   FreeLibrary(m_GdiModule);
    744   FreeLibrary(m_hModule);
    745 }
    746 
    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 
    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 }
    794 void CGdiplusExt::DeleteMemFont(LPVOID pCollection) {
    795   CGdiplusExt& GdiplusExt =
    796       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    797   CallFunc(GdipDeletePrivateFontCollection)((GpFontCollection**)&pCollection);
    798 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    892 void CGdiplusExt::GdipDeleteBrush(void* pBrush) {
    893   CGdiplusExt& GdiplusExt =
    894       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    895   CallFunc(GdipDeleteBrush)((GpSolidFill*)pBrush);
    896 }
    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 }
    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 }
    933 void CGdiplusExt::GdipDeleteMatrix(void* matrix) {
    934   CGdiplusExt& GdiplusExt =
    935       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    936   CallFunc(GdipDeleteMatrix)((GpMatrix*)matrix);
    937 }
    938 void CGdiplusExt::GdipDeleteFontFamily(void* pFamily) {
    939   CGdiplusExt& GdiplusExt =
    940       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    941   CallFunc(GdipDeleteFontFamily)((GpFontFamily*)pFamily);
    942 }
    943 void CGdiplusExt::GdipDeleteFont(void* pFont) {
    944   CGdiplusExt& GdiplusExt =
    945       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    946   CallFunc(GdipDeleteFont)((GpFont*)pFont);
    947 }
    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 }
    953 void CGdiplusExt::GdipDisposeImage(void* bitmap) {
    954   CGdiplusExt& GdiplusExt =
    955       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    956   CallFunc(GdipDisposeImage)((GpBitmap*)bitmap);
    957 }
    958 void CGdiplusExt::GdipDeleteGraphics(void* graphics) {
    959   CGdiplusExt& GdiplusExt =
    960       ((CWin32Platform*)CFX_GEModule::Get()->GetPlatformData())->m_GdiplusExt;
    961   CallFunc(GdipDeleteGraphics)((GpGraphics*)graphics);
    962 }
    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 }
    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 }
   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 }
   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 }
   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:
   1302   GpStream() : m_RefCount(1), m_ReadPos(0) {}
   1303 
   1304   // IUnknown
   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   }
   1315   ULONG STDMETHODCALLTYPE AddRef() override {
   1316     return (ULONG)InterlockedIncrement(&m_RefCount);
   1317   }
   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
   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   }
   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
   1361   HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) override {
   1362     return E_NOTIMPL;
   1363   }
   1364   HRESULT STDMETHODCALLTYPE CopyTo(IStream*,
   1365                                    ULARGE_INTEGER,
   1366                                    ULARGE_INTEGER*,
   1367                                    ULARGE_INTEGER*) override {
   1368     return E_NOTIMPL;
   1369   }
   1370   HRESULT STDMETHODCALLTYPE Commit(DWORD) override { return E_NOTIMPL; }
   1371   HRESULT STDMETHODCALLTYPE Revert() override { return E_NOTIMPL; }
   1372   HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER,
   1373                                        ULARGE_INTEGER,
   1374                                        DWORD) override {
   1375     return E_NOTIMPL;
   1376   }
   1377   HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER,
   1378                                          ULARGE_INTEGER,
   1379                                          DWORD) override {
   1380     return E_NOTIMPL;
   1381   }
   1382   HRESULT STDMETHODCALLTYPE Clone(IStream** stream) override {
   1383     return E_NOTIMPL;
   1384   }
   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   }
   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 
   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 
   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 
   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