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