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 "../../../include/fxge/fx_ge.h"
      8 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_
      9 #include "../../../include/fxge/fx_ge_win32.h"
     10 #include <crtdbg.h>
     11 #include "../agg/include/fxfx_agg_clip_liang_barsky.h"
     12 #include "dwrite_int.h"
     13 #include "win32_int.h"
     14 #include "../ge/text_int.h"
     15 #include "../dib/dib_int.h"
     16 #include "../agg/include/fx_agg_driver.h"
     17 #include "../../../include/fxge/fx_freetype.h"
     18 #include "../../../include/fxcodec/fx_codec.h"
     19 class CWin32FontInfo FX_FINAL : public IFX_SystemFontInfo
     20 {
     21 public:
     22     CWin32FontInfo();
     23     ~CWin32FontInfo();
     24     virtual void		Release();
     25     virtual	FX_BOOL		EnumFontList(CFX_FontMapper* pMapper);
     26     virtual void*		MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR face, FX_BOOL& bExact);
     27     virtual void*		GetFont(FX_LPCSTR face)
     28     {
     29         return NULL;
     30     }
     31     virtual FX_DWORD	GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size);
     32     virtual void		DeleteFont(void* hFont);
     33     virtual	FX_BOOL		GetFaceName(void* hFont, CFX_ByteString& name);
     34     virtual FX_BOOL		GetFontCharset(void* hFont, int& charset);
     35     FX_BOOL				IsOpenTypeFromDiv(const LOGFONTA *plf);
     36     FX_BOOL				IsSupportFontFormDiv(const LOGFONTA* plf);
     37     void				AddInstalledFont(const LOGFONTA *plf, FX_DWORD FontType);
     38     void				GetGBPreference(CFX_ByteString& face, int weight, int picth_family);
     39     void				GetJapanesePreference(CFX_ByteString& face, int weight, int picth_family);
     40     CFX_ByteString		FindFont(const CFX_ByteString& name);
     41     HDC					m_hDC;
     42     CFX_FontMapper*		m_pMapper;
     43     CFX_ByteString		m_LastFamily;
     44     CFX_ByteString		m_KaiTi, m_FangSong;
     45 };
     46 CWin32FontInfo::CWin32FontInfo()
     47 {
     48     m_hDC = CreateCompatibleDC(NULL);
     49 }
     50 CWin32FontInfo::~CWin32FontInfo()
     51 {
     52     m_pMapper = NULL;
     53 }
     54 void CWin32FontInfo::Release()
     55 {
     56     DeleteDC(m_hDC);
     57     delete this;
     58 }
     59 #define TT_MAKE_TAG(x1, x2, x3, x4) (((FX_DWORD)x1<<24)|((FX_DWORD)x2<<16)|((FX_DWORD)x3<<8)|(FX_DWORD)x4)
     60 FX_BOOL CWin32FontInfo::IsOpenTypeFromDiv(const LOGFONTA *plf)
     61 {
     62     HFONT hFont = CreateFontIndirectA(plf);
     63     FX_BOOL ret = FALSE;
     64     FX_DWORD font_size  = GetFontData(hFont, 0, NULL, 0);
     65     if (font_size != GDI_ERROR && font_size >= sizeof(FX_DWORD)) {
     66         FX_DWORD lVersion = 0;
     67         GetFontData(hFont, 0, (FX_BYTE*)(&lVersion), sizeof(FX_DWORD));
     68         lVersion = (((FX_DWORD)(FX_BYTE)(lVersion)) << 24) | ((FX_DWORD)((FX_BYTE)(lVersion >> 8))) << 16 |
     69                    ((FX_DWORD)((FX_BYTE)(lVersion >> 16))) << 8 | ((FX_BYTE)(lVersion >> 24));
     70         if (lVersion == TT_MAKE_TAG('O', 'T', 'T', 'O') ||
     71                 lVersion == 0x00010000 ||
     72                 lVersion == TT_MAKE_TAG('t', 't', 'c', 'f') ||
     73                 lVersion == TT_MAKE_TAG('t', 'r', 'u', 'e') ||
     74                 lVersion == 0x00020000) {
     75             ret = TRUE;
     76         }
     77     }
     78     DeleteFont(hFont);
     79     return ret;
     80 }
     81 FX_BOOL CWin32FontInfo::IsSupportFontFormDiv(const LOGFONTA* plf)
     82 {
     83     HFONT hFont = CreateFontIndirectA(plf);
     84     FX_BOOL ret = FALSE;
     85     FX_DWORD font_size  = GetFontData(hFont, 0, NULL, 0);
     86     if (font_size != GDI_ERROR && font_size >= sizeof(FX_DWORD)) {
     87         FX_DWORD lVersion = 0;
     88         GetFontData(hFont, 0, (FX_BYTE*)(&lVersion), sizeof(FX_DWORD));
     89         lVersion = (((FX_DWORD)(FX_BYTE)(lVersion)) << 24) | ((FX_DWORD)((FX_BYTE)(lVersion >> 8))) << 16 |
     90                    ((FX_DWORD)((FX_BYTE)(lVersion >> 16))) << 8 | ((FX_BYTE)(lVersion >> 24));
     91         if (lVersion == TT_MAKE_TAG('O', 'T', 'T', 'O') ||
     92                 lVersion == 0x00010000 ||
     93                 lVersion == TT_MAKE_TAG('t', 't', 'c', 'f') ||
     94                 lVersion == TT_MAKE_TAG('t', 'r', 'u', 'e') ||
     95                 lVersion == 0x00020000) {
     96             ret = TRUE;
     97         } else if ((lVersion & 0xFFFF0000) == TT_MAKE_TAG(0x80, 0x01, 0x00, 0x00) ||
     98                    (lVersion & 0xFFFF0000) == TT_MAKE_TAG('%', '!', 0, 0)) {
     99             ret = TRUE;
    100         }
    101     }
    102     DeleteFont(hFont);
    103     return ret;
    104 }
    105 void CWin32FontInfo::AddInstalledFont(const LOGFONTA *plf, FX_DWORD FontType)
    106 {
    107     CFX_ByteString name(plf->lfFaceName, -1);
    108     if (name[0] == '@') {
    109         return;
    110     }
    111     if (name == m_LastFamily) {
    112         m_pMapper->AddInstalledFont(name, plf->lfCharSet);
    113         return;
    114     }
    115     if (!(FontType & TRUETYPE_FONTTYPE) && !(FontType & DEVICE_FONTTYPE)) {
    116         return;
    117     }
    118     if (!(FontType & TRUETYPE_FONTTYPE)) {
    119         if (!IsSupportFontFormDiv(plf)) {
    120             return;
    121         }
    122     }
    123     m_pMapper->AddInstalledFont(name, plf->lfCharSet);
    124     m_LastFamily = name;
    125 }
    126 static int CALLBACK FontEnumProc(
    127     const LOGFONTA *plf,
    128     const TEXTMETRICA *lpntme,
    129     FX_DWORD FontType,
    130     LPARAM lParam
    131 )
    132 {
    133     CWin32FontInfo* pFontInfo = (CWin32FontInfo*)lParam;
    134     if (pFontInfo->m_pMapper->GetFontEnumerator()) {
    135         pFontInfo->m_pMapper->GetFontEnumerator()->HitFont();
    136     }
    137     pFontInfo->AddInstalledFont(plf, FontType);
    138     return 1;
    139 }
    140 FX_BOOL CWin32FontInfo::EnumFontList(CFX_FontMapper* pMapper)
    141 {
    142     m_pMapper = pMapper;
    143     LOGFONTA lf;
    144     FXSYS_memset32(&lf, 0, sizeof(LOGFONTA));
    145     lf.lfCharSet = DEFAULT_CHARSET;
    146     lf.lfFaceName[0] = 0;
    147     lf.lfPitchAndFamily = 0;
    148     EnumFontFamiliesExA(m_hDC, &lf, (FONTENUMPROCA)FontEnumProc, (FX_UINTPTR)this, 0);
    149     if (pMapper->GetFontEnumerator()) {
    150         pMapper->GetFontEnumerator()->Finish();
    151     }
    152     return TRUE;
    153 }
    154 static const struct {
    155     FX_LPCSTR	m_pFaceName;
    156     FX_LPCSTR	m_pVariantName;
    157 }
    158 VariantNames[] = {
    159     {"DFKai-SB", "\x19\x6A\x77\x69\xD4\x9A"},
    160 };
    161 static const struct {
    162     FX_LPCSTR	m_pName;
    163     FX_LPCSTR	m_pWinName;
    164     FX_BOOL		m_bBold;
    165     FX_BOOL		m_bItalic;
    166 }
    167 Base14Substs[] = {
    168     {"Courier", "Courier New", FALSE, FALSE},
    169     {"Courier-Bold", "Courier New", TRUE, FALSE},
    170     {"Courier-BoldOblique", "Courier New", TRUE, TRUE},
    171     {"Courier-Oblique", "Courier New", FALSE, TRUE},
    172     {"Helvetica", "Arial", FALSE, FALSE},
    173     {"Helvetica-Bold", "Arial", TRUE, FALSE},
    174     {"Helvetica-BoldOblique", "Arial", TRUE, TRUE},
    175     {"Helvetica-Oblique", "Arial", FALSE, TRUE},
    176     {"Times-Roman", "Times New Roman", FALSE, FALSE},
    177     {"Times-Bold", "Times New Roman", TRUE, FALSE},
    178     {"Times-BoldItalic", "Times New Roman", TRUE, TRUE},
    179     {"Times-Italic", "Times New Roman", FALSE, TRUE},
    180 };
    181 CFX_ByteString CWin32FontInfo::FindFont(const CFX_ByteString& name)
    182 {
    183     if (m_pMapper == NULL) {
    184         return name;
    185     }
    186     int nFonts = m_pMapper->m_InstalledTTFonts.GetSize();
    187     for (int i = 0; i < nFonts; i ++) {
    188         CFX_ByteString thisname = m_pMapper->m_InstalledTTFonts[i];
    189         if (thisname[0] == ' ') {
    190             if (thisname.Mid(1, name.GetLength()) == name) {
    191                 return m_pMapper->m_InstalledTTFonts[i + 1];
    192             }
    193         } else if (thisname.Left(name.GetLength()) == name) {
    194             return m_pMapper->m_InstalledTTFonts[i];
    195         }
    196     }
    197     return CFX_ByteString();
    198 }
    199 struct _FontNameMap {
    200     FX_LPCSTR	m_pSubFontName;
    201     FX_LPCSTR	m_pSrcFontName;
    202 };
    203 const _FontNameMap g_JpFontNameMap[] = {
    204     {"MS Mincho", "Heiseimin-W3"},
    205     {"MS Gothic", "Jun101-Light"},
    206 };
    207 extern "C" {
    208     static int compareString(const void* key, const void* element)
    209     {
    210         return FXSYS_stricmp((FX_LPCSTR)key, ((_FontNameMap*)element)->m_pSrcFontName);
    211     }
    212 }
    213 FX_BOOL _GetSubFontName(CFX_ByteString& name)
    214 {
    215     int size = sizeof g_JpFontNameMap;
    216     void* pFontnameMap = (void*)g_JpFontNameMap;
    217     _FontNameMap* found = (_FontNameMap*)FXSYS_bsearch(name.c_str(), pFontnameMap,
    218                           size / sizeof (_FontNameMap), sizeof (_FontNameMap), compareString);
    219     if (found == NULL) {
    220         return FALSE;
    221     }
    222     name = found->m_pSubFontName;
    223     return TRUE;
    224 }
    225 void CWin32FontInfo::GetGBPreference(CFX_ByteString& face, int weight, int picth_family)
    226 {
    227     if (face.Find("KaiTi") >= 0 || face.Find("\xbf\xac") >= 0) {
    228         if (m_KaiTi.IsEmpty()) {
    229             m_KaiTi = FindFont("KaiTi");
    230             if (m_KaiTi.IsEmpty()) {
    231                 m_KaiTi = "SimSun";
    232             }
    233         }
    234         face = m_KaiTi;
    235     } else if (face.Find("FangSong") >= 0 || face.Find("\xb7\xc2\xcb\xce") >= 0) {
    236         if (m_FangSong.IsEmpty()) {
    237             m_FangSong = FindFont("FangSong");
    238             if (m_FangSong.IsEmpty()) {
    239                 m_FangSong = "SimSun";
    240             }
    241         }
    242         face = m_FangSong;
    243     } else if (face.Find("SimSun") >= 0 || face.Find("\xcb\xce") >= 0) {
    244         face = "SimSun";
    245     } else if (face.Find("SimHei") >= 0 || face.Find("\xba\xda") >= 0) {
    246         face = "SimHei";
    247     } else if (!(picth_family & FF_ROMAN) && weight > 550) {
    248         face = "SimHei";
    249     } else {
    250         face = "SimSun";
    251     }
    252 }
    253 void CWin32FontInfo::GetJapanesePreference(CFX_ByteString& face, int weight, int picth_family)
    254 {
    255     if (face.Find("Gothic") >= 0 || face.Find("\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) {
    256         if (face.Find("PGothic") >= 0 || face.Find("\x82\x6f\x83\x53\x83\x56\x83\x62\x83\x4e") >= 0) {
    257             face = "MS PGothic";
    258         } else if (face.Find("UI Gothic") >= 0) {
    259             face = "MS UI Gothic";
    260         } else {
    261             if (face.Find("HGSGothicM") >= 0 || face.Find("HGMaruGothicMPRO") >= 0) {
    262                 face = "MS PGothic";
    263             } else {
    264                 face = "MS Gothic";
    265             }
    266         }
    267         return;
    268     } else if (face.Find("Mincho") >= 0 || face.Find("\x96\xbe\x92\xa9") >= 0) {
    269         if (face.Find("PMincho") >= 0 || face.Find("\x82\x6f\x96\xbe\x92\xa9") >= 0) {
    270             face = "MS PMincho";
    271         } else {
    272             face = "MS Mincho";
    273         }
    274         return;
    275     }
    276     if (_GetSubFontName(face)) {
    277         return;
    278     }
    279     if (!(picth_family & FF_ROMAN) && weight > 400) {
    280         face = "MS PGothic";
    281     } else {
    282         face = "MS PMincho";
    283     }
    284 }
    285 void* CWin32FontInfo::MapFont(int weight, FX_BOOL bItalic, int charset, int pitch_family, FX_LPCSTR cstr_face, FX_BOOL& bExact)
    286 {
    287     CFX_ByteString face = cstr_face;
    288     int iBaseFont;
    289     for (iBaseFont = 0; iBaseFont < 12; iBaseFont ++)
    290         if (face == CFX_ByteStringC(Base14Substs[iBaseFont].m_pName)) {
    291             face = Base14Substs[iBaseFont].m_pWinName;
    292             weight = Base14Substs[iBaseFont].m_bBold ? FW_BOLD : FW_NORMAL;
    293             bItalic = Base14Substs[iBaseFont].m_bItalic;
    294             bExact = TRUE;
    295             break;
    296         }
    297     if (charset == ANSI_CHARSET || charset == SYMBOL_CHARSET) {
    298         charset = DEFAULT_CHARSET;
    299     }
    300     int subst_pitch_family = pitch_family;
    301     switch (charset) {
    302         case SHIFTJIS_CHARSET:
    303             subst_pitch_family = FF_ROMAN;
    304             break;
    305         case CHINESEBIG5_CHARSET:
    306         case HANGUL_CHARSET:
    307         case GB2312_CHARSET:
    308             subst_pitch_family = 0;
    309             break;
    310     }
    311     HFONT hFont = ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset, OUT_TT_ONLY_PRECIS,
    312                                 0, 0, subst_pitch_family, face);
    313     char facebuf[100];
    314     HFONT hOldFont = (HFONT)::SelectObject(m_hDC, hFont);
    315     int ret = ::GetTextFaceA(m_hDC, 100, facebuf);
    316     ::SelectObject(m_hDC, hOldFont);
    317     if (face.EqualNoCase(facebuf)) {
    318         return hFont;
    319     }
    320     int iCount = sizeof(VariantNames) / sizeof(VariantNames[0]);
    321     for (int i = 0; i < iCount; ++i) {
    322         if (face == VariantNames[i].m_pFaceName) {
    323             CFX_WideString wsFace = CFX_WideString::FromLocal(facebuf);
    324             const unsigned short* pName = (const unsigned short*)VariantNames[i].m_pVariantName;
    325             FX_STRSIZE len = CFX_WideString::WStringLength(pName);
    326             CFX_WideString wsName = CFX_WideString::FromUTF16LE(pName, len);
    327             if (wsFace == wsName) {
    328                 return hFont;
    329             }
    330         }
    331     }
    332     ::DeleteObject(hFont);
    333     if (charset == DEFAULT_CHARSET) {
    334         return NULL;
    335     }
    336     switch (charset) {
    337         case SHIFTJIS_CHARSET:
    338             GetJapanesePreference(face, weight, pitch_family);
    339             break;
    340         case GB2312_CHARSET:
    341             GetGBPreference(face, weight, pitch_family);
    342             break;
    343         case HANGUL_CHARSET:
    344             face = "Gulim";
    345             break;
    346         case CHINESEBIG5_CHARSET:
    347             if (face.Find("MSung") >= 0) {
    348                 face = "MingLiU";
    349             } else {
    350                 face = "PMingLiU";
    351             }
    352             break;
    353     }
    354     hFont = ::CreateFontA(-10, 0, 0, 0, weight, bItalic, 0, 0, charset, OUT_TT_ONLY_PRECIS,
    355                           0, 0, subst_pitch_family, face);
    356     return hFont;
    357 }
    358 void CWin32FontInfo::DeleteFont(void* hFont)
    359 {
    360     ::DeleteObject(hFont);
    361 }
    362 FX_DWORD CWin32FontInfo::GetFontData(void* hFont, FX_DWORD table, FX_LPBYTE buffer, FX_DWORD size)
    363 {
    364     HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
    365     table = FXDWORD_FROM_MSBFIRST(table);
    366     size = ::GetFontData(m_hDC, table, 0, buffer, size);
    367     ::SelectObject(m_hDC, hOldFont);
    368     if (size == GDI_ERROR) {
    369         return 0;
    370     }
    371     return size;
    372 }
    373 FX_BOOL CWin32FontInfo::GetFaceName(void* hFont, CFX_ByteString& name)
    374 {
    375     char facebuf[100];
    376     HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
    377     int ret = ::GetTextFaceA(m_hDC, 100, facebuf);
    378     ::SelectObject(m_hDC, hOldFont);
    379     if (ret == 0) {
    380         return FALSE;
    381     }
    382     name = facebuf;
    383     return TRUE;
    384 }
    385 FX_BOOL CWin32FontInfo::GetFontCharset(void* hFont, int& charset)
    386 {
    387     TEXTMETRIC tm;
    388     HFONT hOldFont = (HFONT)::SelectObject(m_hDC, (HFONT)hFont);
    389     ::GetTextMetrics(m_hDC, &tm);
    390     ::SelectObject(m_hDC, hOldFont);
    391     charset = tm.tmCharSet;
    392     return TRUE;
    393 }
    394 IFX_SystemFontInfo* IFX_SystemFontInfo::CreateDefault()
    395 {
    396     return new CWin32FontInfo;
    397 }
    398 void CFX_GEModule::InitPlatform()
    399 {
    400     CWin32Platform* pPlatformData = new CWin32Platform;
    401     OSVERSIONINFO ver;
    402     ver.dwOSVersionInfoSize = sizeof(ver);
    403     GetVersionEx(&ver);
    404     pPlatformData->m_bHalfTone = ver.dwMajorVersion >= 5;
    405     pPlatformData->m_GdiplusExt.Load();
    406     m_pPlatformData = pPlatformData;
    407     m_pFontMgr->SetSystemFontInfo(IFX_SystemFontInfo::CreateDefault());
    408 }
    409 void CFX_GEModule::DestroyPlatform()
    410 {
    411     if (m_pPlatformData) {
    412         delete (CWin32Platform*)m_pPlatformData;
    413     }
    414     m_pPlatformData = NULL;
    415 }
    416 CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, int device_class)
    417 {
    418     m_hDC = hDC;
    419     m_DeviceClass = device_class;
    420     CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();
    421     SetStretchBltMode(hDC, pPlatform->m_bHalfTone ? HALFTONE : COLORONCOLOR);
    422     if (GetObjectType(m_hDC) == OBJ_MEMDC) {
    423         HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, NULL);
    424         hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
    425         BITMAP bitmap;
    426         GetObject(hBitmap, sizeof bitmap, &bitmap);
    427         m_nBitsPerPixel = bitmap.bmBitsPixel;
    428         m_Width = bitmap.bmWidth;
    429         m_Height = abs(bitmap.bmHeight);
    430         hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
    431         DeleteObject(hBitmap);
    432     } else {
    433         m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
    434         m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
    435         m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
    436     }
    437     if (m_DeviceClass != FXDC_DISPLAY) {
    438         m_RenderCaps = FXRC_BIT_MASK;
    439     } else {
    440         m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK;
    441     }
    442 }
    443 int CGdiDeviceDriver::GetDeviceCaps(int caps_id)
    444 {
    445     switch (caps_id) {
    446         case FXDC_DEVICE_CLASS:
    447             return m_DeviceClass;
    448         case FXDC_PIXEL_WIDTH:
    449             return m_Width;
    450         case FXDC_PIXEL_HEIGHT:
    451             return m_Height;
    452         case FXDC_BITS_PIXEL:
    453             return m_nBitsPerPixel;
    454         case FXDC_RENDER_CAPS:
    455             return m_RenderCaps;
    456     }
    457     return 0;
    458 }
    459 FX_LPVOID CGdiDeviceDriver::GetClipRgn()
    460 {
    461     HRGN hClipRgn = CreateRectRgn(0, 0, 1, 1);
    462     if (::GetClipRgn(m_hDC, hClipRgn) == 0) {
    463         DeleteObject(hClipRgn);
    464         hClipRgn = NULL;
    465     }
    466     return (FX_LPVOID)hClipRgn;
    467 }
    468 FX_BOOL CGdiDeviceDriver::GDI_SetDIBits(const CFX_DIBitmap* pBitmap1, const FX_RECT* pSrcRect, int left, int top, void* pIccTransform)
    469 {
    470     if (m_DeviceClass == FXDC_PRINTER) {
    471         CFX_DIBitmap* pBitmap = pBitmap1->FlipImage(FALSE, TRUE);
    472         if (pBitmap == NULL) {
    473             return FALSE;
    474         }
    475         if ((pBitmap->IsCmykImage() || pIccTransform) &&
    476                 !pBitmap->ConvertFormat(FXDIB_Rgb, pIccTransform)) {
    477             return FALSE;
    478         }
    479         int width = pSrcRect->Width(), height = pSrcRect->Height();
    480         int pitch = pBitmap->GetPitch();
    481         LPBYTE pBuffer = pBitmap->GetBuffer();
    482         CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
    483         ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
    484         FX_RECT dst_rect(0, 0, width, height);
    485         dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
    486         int dst_width = dst_rect.Width();
    487         int dst_height = dst_rect.Height();
    488         ::StretchDIBits(m_hDC, left, top, dst_width, dst_height,
    489             0, 0, dst_width, dst_height, pBuffer, (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS, SRCCOPY);
    490         delete pBitmap;
    491     } else {
    492         CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1;
    493         if ((pBitmap->IsCmykImage() || pIccTransform) &&
    494                 (pBitmap = pBitmap->CloneConvert(FXDIB_Rgb, NULL, pIccTransform)) == NULL) {
    495             return FALSE;
    496         }
    497         int width = pSrcRect->Width(), height = pSrcRect->Height();
    498         int pitch = pBitmap->GetPitch();
    499         LPBYTE pBuffer = pBitmap->GetBuffer();
    500         CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
    501         ::SetDIBitsToDevice(m_hDC, left, top, width, height, pSrcRect->left, pBitmap->GetHeight() - pSrcRect->bottom,
    502             0, pBitmap->GetHeight(), pBuffer, (BITMAPINFO*)info.c_str(), DIB_RGB_COLORS);
    503         if (pBitmap != pBitmap1) {
    504             delete pBitmap;
    505         }
    506     }
    507     return TRUE;
    508 }
    509 FX_BOOL CGdiDeviceDriver::GDI_StretchDIBits(const CFX_DIBitmap* pBitmap1, int dest_left, int dest_top,
    510         int dest_width, int dest_height, FX_DWORD flags, void* pIccTransform)
    511 {
    512     CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1;
    513     if (pBitmap == NULL || dest_width == 0  || dest_height == 0) {
    514         return FALSE;
    515     }
    516     if ((pBitmap->IsCmykImage() || pIccTransform) &&
    517             !pBitmap->ConvertFormat(FXDIB_Rgb, pIccTransform)) {
    518         return FALSE;
    519     }
    520     CFX_ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
    521     if ((FX_INT64)abs(dest_width) * abs(dest_height) < (FX_INT64)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 ||
    522             (flags & FXDIB_INTERPOL) || (flags & FXDIB_BICUBIC_INTERPOL)) {
    523         SetStretchBltMode(m_hDC, HALFTONE);
    524     } else {
    525         SetStretchBltMode(m_hDC, COLORONCOLOR);
    526     }
    527     CFX_DIBitmap* pToStrechBitmap = pBitmap;
    528     bool del = false;
    529     if (m_DeviceClass == FXDC_PRINTER && ((FX_INT64)pBitmap->GetWidth() * pBitmap->GetHeight() > (FX_INT64)abs(dest_width) * abs(dest_height))) {
    530         pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height);
    531         del = true;
    532     }
    533     CFX_ByteString toStrechBitmapInfo = CFX_WindowsDIB::GetBitmapInfo(pToStrechBitmap);
    534     ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height,
    535                     0, 0, pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(), pToStrechBitmap->GetBuffer(),
    536                     (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS, SRCCOPY);
    537     if (del) {
    538         delete pToStrechBitmap;
    539     }
    540     return TRUE;
    541 }
    542 FX_BOOL CGdiDeviceDriver::GDI_StretchBitMask(const CFX_DIBitmap* pBitmap1, int dest_left, int dest_top,
    543         int dest_width, int dest_height, FX_DWORD bitmap_color, FX_DWORD flags,
    544         int alpha_flag, void* pIccTransform)
    545 {
    546     CFX_DIBitmap* pBitmap = (CFX_DIBitmap*)pBitmap1;
    547     if (pBitmap == NULL || dest_width == 0  || dest_height == 0) {
    548         return FALSE;
    549     }
    550     _Color2Argb(bitmap_color, bitmap_color, alpha_flag | (1 << 24), pIccTransform);
    551     int width = pBitmap->GetWidth(), height = pBitmap->GetHeight();
    552     struct {
    553         BITMAPINFOHEADER	bmiHeader;
    554         FX_DWORD			bmiColors[2];
    555     } bmi;
    556     FXSYS_memset32(&bmi.bmiHeader, 0, sizeof (BITMAPINFOHEADER));
    557     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    558     bmi.bmiHeader.biBitCount = 1;
    559     bmi.bmiHeader.biCompression = BI_RGB;
    560     bmi.bmiHeader.biHeight = -height;
    561     bmi.bmiHeader.biPlanes = 1;
    562     bmi.bmiHeader.biWidth = width;
    563     if (m_nBitsPerPixel != 1) {
    564         SetStretchBltMode(m_hDC, HALFTONE);
    565     }
    566     bmi.bmiColors[0] = 0xffffff;
    567     bmi.bmiColors[1] = 0;
    568 
    569     HBRUSH hPattern = CreateSolidBrush(bitmap_color & 0xffffff);
    570     HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
    571 
    572 
    573     // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush bitmap.
    574     // A complete list of the boolen operations is as follows:
    575 
    576     /* P(bitmap_color)    S(ImageMask)    D(DeviceBitmap)    Result
    577      *        0                 0                0              0
    578      *        0                 0                1              0
    579      *        0                 1                0              0
    580      *        0                 1                1              1
    581      *        1                 0                0              1
    582      *        1                 0                1              1
    583      *        1                 1                0              0
    584      *        1                 1                1              1
    585      */
    586     // The boolen codes is B8. Based on http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is 0xB8074A
    587 
    588     ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height,
    589                     0, 0, width, height, pBitmap->GetBuffer(), (BITMAPINFO*)&bmi, DIB_RGB_COLORS, 0xB8074A);
    590 
    591     SelectObject(m_hDC, hOld);
    592     DeleteObject(hPattern);
    593 
    594     return TRUE;
    595 }
    596 BOOL CGdiDeviceDriver::GetClipBox(FX_RECT* pRect)
    597 {
    598     return ::GetClipBox(m_hDC, (RECT*)pRect);
    599 }
    600 FX_BOOL CGdiDeviceDriver::SetClipRgn(FX_LPVOID hRgn)
    601 {
    602     ::SelectClipRgn(m_hDC, (HRGN)hRgn);
    603     return TRUE;
    604 }
    605 static HPEN _CreatePen(const CFX_GraphStateData* pGraphState, const CFX_AffineMatrix* pMatrix, FX_DWORD argb)
    606 {
    607     FX_FLOAT width;
    608     FX_FLOAT scale = 1.f;
    609     if (pMatrix)
    610         scale = FXSYS_fabs(pMatrix->a) > FXSYS_fabs(pMatrix->b) ?
    611                 FXSYS_fabs(pMatrix->a) : FXSYS_fabs(pMatrix->b);
    612     if (pGraphState) {
    613         width = scale * pGraphState->m_LineWidth;
    614     } else {
    615         width = 1.0f;
    616     }
    617     FX_DWORD PenStyle = PS_GEOMETRIC;
    618     if (width < 1) {
    619         width = 1;
    620     }
    621     if(pGraphState->m_DashCount) {
    622         PenStyle |= PS_USERSTYLE;
    623     } else {
    624         PenStyle |= PS_SOLID;
    625     }
    626     switch(pGraphState->m_LineCap) {
    627         case 0:
    628             PenStyle |= PS_ENDCAP_FLAT;
    629             break;
    630         case 1:
    631             PenStyle |= PS_ENDCAP_ROUND;
    632             break;
    633         case 2:
    634             PenStyle |= PS_ENDCAP_SQUARE;
    635             break;
    636     }
    637     switch(pGraphState->m_LineJoin) {
    638         case 0:
    639             PenStyle |= PS_JOIN_MITER;
    640             break;
    641         case 1:
    642             PenStyle |= PS_JOIN_ROUND;
    643             break;
    644         case 2:
    645             PenStyle |= PS_JOIN_BEVEL;
    646             break;
    647     }
    648     int a;
    649     FX_COLORREF rgb;
    650     ArgbDecode(argb, a, rgb);
    651     LOGBRUSH lb;
    652     lb.lbColor = rgb;
    653     lb.lbStyle = BS_SOLID;
    654     lb.lbHatch = 0;
    655     FX_DWORD* pDash = NULL;
    656     if (pGraphState->m_DashCount) {
    657         pDash = FX_Alloc(FX_DWORD, pGraphState->m_DashCount);
    658         for (int i = 0; i < pGraphState->m_DashCount; i ++) {
    659             pDash[i] = FXSYS_round(pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i]) : pGraphState->m_DashArray[i]);
    660             if (pDash[i] < 1) {
    661                 pDash[i] = 1;
    662             }
    663         }
    664     }
    665     HPEN hPen = ExtCreatePen(PenStyle, (DWORD)FXSYS_ceil(width), &lb, pGraphState->m_DashCount, (const DWORD*)pDash);
    666     if (pDash) {
    667         FX_Free(pDash);
    668     }
    669     return hPen;
    670 }
    671 static HBRUSH _CreateBrush(FX_DWORD argb)
    672 {
    673     int a;
    674     FX_COLORREF rgb;
    675     ArgbDecode(argb, a, rgb);
    676     return CreateSolidBrush(rgb);
    677 }
    678 static void _SetPathToDC(HDC hDC, const CFX_PathData* pPathData, const CFX_AffineMatrix* pMatrix)
    679 {
    680     BeginPath(hDC);
    681     int nPoints = pPathData->GetPointCount();
    682     FX_PATHPOINT* pPoints = pPathData->GetPoints();
    683     for(int i = 0; i < nPoints; i++) {
    684         FX_FLOAT posx = pPoints[i].m_PointX, posy = pPoints[i].m_PointY;
    685         if (pMatrix) {
    686             pMatrix->Transform(posx, posy);
    687         }
    688         int screen_x = FXSYS_round(posx), screen_y = FXSYS_round(posy);
    689         int point_type = pPoints[i].m_Flag & FXPT_TYPE;
    690         if(point_type == PT_MOVETO) {
    691             MoveToEx(hDC, screen_x, screen_y, NULL);
    692         } else if(point_type == PT_LINETO) {
    693             if (pPoints[i].m_PointY == pPoints[i - 1].m_PointY && pPoints[i].m_PointX == pPoints[i - 1].m_PointX) {
    694                 screen_x ++;
    695             }
    696             LineTo(hDC, screen_x, screen_y);
    697         } else if(point_type == PT_BEZIERTO) {
    698             POINT lppt[3];
    699             lppt[0].x = screen_x;
    700             lppt[0].y = screen_y;
    701             posx = pPoints[i + 1].m_PointX;
    702             posy = pPoints[i + 1].m_PointY;
    703             if (pMatrix) {
    704                 pMatrix->Transform(posx, posy);
    705             }
    706             lppt[1].x = FXSYS_round(posx);
    707             lppt[1].y = FXSYS_round(posy);
    708             posx = pPoints[i + 2].m_PointX;
    709             posy = pPoints[i + 2].m_PointY;
    710             if (pMatrix) {
    711                 pMatrix->Transform(posx, posy);
    712             }
    713             lppt[2].x = FXSYS_round(posx);
    714             lppt[2].y = FXSYS_round(posy);
    715             PolyBezierTo(hDC, lppt, 3);
    716             i += 2;
    717         }
    718         if (pPoints[i].m_Flag & PT_CLOSEFIGURE) {
    719             CloseFigure(hDC);
    720         }
    721     }
    722     EndPath(hDC);
    723 }
    724 void CGdiDeviceDriver::DrawLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2)
    725 {
    726     int flag1 = (x1 < 0) | ((x1 > m_Width) << 1) | ((y1 < 0) << 2) | ((y1 > m_Height) << 3);
    727     int flag2 = (x2 < 0) | ((x2 > m_Width) << 1) | ((y2 < 0) << 2) | ((y2 > m_Height) << 3);
    728     if (flag1 & flag2) {
    729         return;
    730     }
    731     if (flag1 || flag2) {
    732         agg::rect_base<FX_FLOAT> rect(0.0f, 0.0f, (FX_FLOAT)(m_Width), (FX_FLOAT)(m_Height));
    733         FX_FLOAT x[2], y[2];
    734         int np = agg::clip_liang_barsky<FX_FLOAT>(x1, y1, x2, y2, rect, x, y);
    735         if (np == 0) {
    736             return;
    737         }
    738         if (np == 1) {
    739             x2 = x[0];
    740             y2 = y[0];
    741         } else {
    742             x1 = x[0];
    743             y1 = y[0];
    744             x2 = x[np - 1];
    745             y2 = y[np - 1];
    746         }
    747     }
    748     MoveToEx(m_hDC, FXSYS_round(x1), FXSYS_round(y1), NULL);
    749     LineTo(m_hDC, FXSYS_round(x2), FXSYS_round(y2));
    750 }
    751 static FX_BOOL _MatrixNoScaled(const CFX_AffineMatrix* pMatrix)
    752 {
    753     return pMatrix->GetA() == 1.0f && pMatrix->GetB() == 0 && pMatrix->GetC() == 0 && pMatrix->GetD() == 1.0f;
    754 }
    755 FX_BOOL CGdiDeviceDriver::DrawPath(const CFX_PathData* pPathData,
    756                                    const CFX_AffineMatrix* pMatrix,
    757                                    const CFX_GraphStateData* pGraphState,
    758                                    FX_DWORD fill_color,
    759                                    FX_DWORD stroke_color,
    760                                    int fill_mode,
    761                                    int alpha_flag,
    762                                    void* pIccTransform,
    763                                    int	blend_type
    764                                   )
    765 {
    766     if (blend_type != FXDIB_BLEND_NORMAL) {
    767         return FALSE;
    768     }
    769     _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
    770     _Color2Argb(stroke_color, stroke_color, alpha_flag, pIccTransform);
    771     CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();
    772     if ((pGraphState == NULL || stroke_color == 0) && !pPlatform->m_GdiplusExt.IsAvailable()) {
    773         CFX_FloatRect bbox_f = pPathData->GetBoundingBox();
    774         if (pMatrix) {
    775             bbox_f.Transform(pMatrix);
    776         }
    777         FX_RECT bbox = bbox_f.GetInnerRect();
    778         if (bbox.Width() <= 0) {
    779             return DrawCosmeticLine((FX_FLOAT)(bbox.left), (FX_FLOAT)(bbox.top), (FX_FLOAT)(bbox.left), (FX_FLOAT)(bbox.bottom + 1), fill_color,
    780                                     alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL);
    781         } else if (bbox.Height() <= 0) {
    782             return DrawCosmeticLine((FX_FLOAT)(bbox.left), (FX_FLOAT)(bbox.top), (FX_FLOAT)(bbox.right + 1), (FX_FLOAT)(bbox.top), fill_color,
    783                                     alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL);
    784         }
    785     }
    786     int fill_alpha = FXARGB_A(fill_color);
    787     int stroke_alpha = FXARGB_A(stroke_color);
    788     FX_BOOL bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) || (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
    789     if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha) {
    790         return FALSE;
    791     }
    792     if (pPlatform->m_GdiplusExt.IsAvailable()) {
    793         if (bDrawAlpha || ((m_DeviceClass != FXDC_PRINTER && !(fill_mode & FXFILL_FULLCOVER)) || pGraphState && pGraphState->m_DashCount)) {
    794             if ( !((NULL == pMatrix || _MatrixNoScaled(pMatrix)) &&
    795                     pGraphState && pGraphState->m_LineWidth == 1.f &&
    796                     (pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) &&
    797                     pPathData->IsRect()) ) {
    798                 if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix, pGraphState, fill_color, stroke_color, fill_mode)) {
    799                     return TRUE;
    800                 }
    801             }
    802         }
    803     }
    804     int old_fill_mode = fill_mode;
    805     fill_mode &= 3;
    806     HPEN hPen = NULL;
    807     HBRUSH hBrush = NULL;
    808     if (pGraphState && stroke_alpha) {
    809         SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, NULL);
    810         hPen = _CreatePen(pGraphState, pMatrix, stroke_color);
    811         hPen = (HPEN)SelectObject(m_hDC, hPen);
    812     }
    813     if (fill_mode && fill_alpha) {
    814         SetPolyFillMode(m_hDC, fill_mode);
    815         hBrush = _CreateBrush(fill_color);
    816         hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
    817     }
    818     if (pPathData->GetPointCount() == 2 && pGraphState && pGraphState->m_DashCount) {
    819         FX_FLOAT x1 = pPathData->GetPointX(0), y1 = pPathData->GetPointY(0);
    820         if (pMatrix) {
    821             pMatrix->Transform(x1, y1);
    822         }
    823         FX_FLOAT x2 = pPathData->GetPointX(1), y2 = pPathData->GetPointY(1);
    824         if (pMatrix) {
    825             pMatrix->Transform(x2, y2);
    826         }
    827         DrawLine(x1, y1, x2, y2);
    828     } else {
    829         _SetPathToDC(m_hDC, pPathData, pMatrix);
    830         if (pGraphState && stroke_alpha) {
    831             if (fill_mode && fill_alpha) {
    832                 if (old_fill_mode & FX_FILL_TEXT_MODE) {
    833                     StrokeAndFillPath(m_hDC);
    834                 } else {
    835                     FillPath(m_hDC);
    836                     _SetPathToDC(m_hDC, pPathData, pMatrix);
    837                     StrokePath(m_hDC);
    838                 }
    839             } else {
    840                 StrokePath(m_hDC);
    841             }
    842         } else if (fill_mode && fill_alpha) {
    843             FillPath(m_hDC);
    844         }
    845     }
    846     if (hPen) {
    847         hPen = (HPEN)SelectObject(m_hDC, hPen);
    848         DeleteObject(hPen);
    849     }
    850     if (hBrush) {
    851         hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
    852         DeleteObject(hBrush);
    853     }
    854     return TRUE;
    855 }
    856 FX_BOOL CGdiDeviceDriver::FillRect(const FX_RECT* pRect, FX_DWORD fill_color, int alpha_flag, void* pIccTransform, int blend_type)
    857 {
    858     if (blend_type != FXDIB_BLEND_NORMAL) {
    859         return FALSE;
    860     }
    861     _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
    862     int alpha;
    863     FX_COLORREF rgb;
    864     ArgbDecode(fill_color, alpha, rgb);
    865     if (alpha == 0) {
    866         return TRUE;
    867     }
    868     if (alpha < 255) {
    869         return FALSE;
    870     }
    871     HBRUSH hBrush = CreateSolidBrush(rgb);
    872     ::FillRect(m_hDC, (RECT*)pRect, hBrush);
    873     DeleteObject(hBrush);
    874     return TRUE;
    875 }
    876 FX_BOOL CGdiDeviceDriver::SetClip_PathFill(const CFX_PathData* pPathData,
    877         const CFX_AffineMatrix* pMatrix,
    878         int fill_mode
    879                                           )
    880 {
    881     if (pPathData->GetPointCount() == 5) {
    882         CFX_FloatRect rectf;
    883         if (pPathData->IsRect(pMatrix, &rectf)) {
    884             FX_RECT rect = rectf.GetOutterRect();
    885             IntersectClipRect(m_hDC, rect.left, rect.top, rect.right, rect.bottom);
    886             return TRUE;
    887         }
    888     }
    889     _SetPathToDC(m_hDC, pPathData, pMatrix);
    890     SetPolyFillMode(m_hDC, fill_mode & 3);
    891     SelectClipPath(m_hDC, RGN_AND);
    892     return TRUE;
    893 }
    894 FX_BOOL CGdiDeviceDriver::SetClip_PathStroke(const CFX_PathData* pPathData,
    895         const CFX_AffineMatrix* pMatrix,
    896         const CFX_GraphStateData* pGraphState
    897                                             )
    898 {
    899     HPEN hPen = _CreatePen(pGraphState, pMatrix, 0xff000000);
    900     hPen = (HPEN)SelectObject(m_hDC, hPen);
    901     _SetPathToDC(m_hDC, pPathData, pMatrix);
    902     WidenPath(m_hDC);
    903     SetPolyFillMode(m_hDC, WINDING);
    904     FX_BOOL ret = SelectClipPath(m_hDC, RGN_AND);
    905     hPen = (HPEN)SelectObject(m_hDC, hPen);
    906     DeleteObject(hPen);
    907     return ret;
    908 }
    909 FX_BOOL CGdiDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2, FX_DWORD color,
    910         int alpha_flag, void* pIccTransform, int	blend_type)
    911 {
    912     if (blend_type != FXDIB_BLEND_NORMAL) {
    913         return FALSE;
    914     }
    915     _Color2Argb(color, color, alpha_flag | (1 << 24), pIccTransform);
    916     int a;
    917     FX_COLORREF rgb;
    918     ArgbDecode(color, a, rgb);
    919     if (a == 0) {
    920         return TRUE;
    921     }
    922     HPEN hPen = CreatePen(PS_SOLID, 1, rgb);
    923     hPen = (HPEN)SelectObject(m_hDC, hPen);
    924     MoveToEx(m_hDC, FXSYS_round(x1), FXSYS_round(y1), NULL);
    925     LineTo(m_hDC, FXSYS_round(x2), FXSYS_round(y2));
    926     hPen = (HPEN)SelectObject(m_hDC, hPen);
    927     DeleteObject(hPen);
    928     return TRUE;
    929 }
    930 FX_BOOL CGdiDeviceDriver::DeleteDeviceRgn(FX_LPVOID pRgn)
    931 {
    932     DeleteObject((HGDIOBJ)pRgn);
    933     return TRUE;
    934 }
    935 CGdiDisplayDriver::CGdiDisplayDriver(HDC hDC) : CGdiDeviceDriver(hDC, FXDC_DISPLAY)
    936 {
    937     CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();
    938     if (pPlatform->m_GdiplusExt.IsAvailable()) {
    939         m_RenderCaps |= FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE;
    940     }
    941 }
    942 FX_BOOL CGdiDisplayDriver::GetDIBits(CFX_DIBitmap* pBitmap, int left, int top, void* pIccTransform, FX_BOOL bDEdge)
    943 {
    944     FX_BOOL ret = FALSE;
    945     int width = pBitmap->GetWidth();
    946     int height = pBitmap->GetHeight();
    947     HBITMAP hbmp = CreateCompatibleBitmap(m_hDC, width, height);
    948     HDC hDCMemory = CreateCompatibleDC(m_hDC);
    949     HBITMAP holdbmp  = (HBITMAP)SelectObject(hDCMemory, hbmp);
    950     BitBlt(hDCMemory, 0, 0, width, height, m_hDC, left, top, SRCCOPY);
    951     SelectObject(hDCMemory, holdbmp);
    952     BITMAPINFO bmi;
    953     FXSYS_memset32(&bmi, 0, sizeof bmi);
    954     bmi.bmiHeader.biSize = sizeof bmi.bmiHeader;
    955     bmi.bmiHeader.biBitCount = pBitmap->GetBPP();
    956     bmi.bmiHeader.biHeight = -height;
    957     bmi.bmiHeader.biPlanes = 1;
    958     bmi.bmiHeader.biWidth = width;
    959     if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
    960         pIccTransform = NULL;
    961     }
    962     if (pBitmap->GetBPP() > 8 && !pBitmap->IsCmykImage() && pIccTransform == NULL) {
    963         ret = ::GetDIBits(hDCMemory, hbmp, 0, height, pBitmap->GetBuffer(), &bmi, DIB_RGB_COLORS) == height;
    964     } else {
    965         CFX_DIBitmap bitmap;
    966         if (bitmap.Create(width, height, FXDIB_Rgb)) {
    967             bmi.bmiHeader.biBitCount = 24;
    968             ::GetDIBits(hDCMemory, hbmp, 0, height, bitmap.GetBuffer(), &bmi, DIB_RGB_COLORS);
    969             ret = pBitmap->TransferBitmap(0, 0, width, height, &bitmap, 0, 0, pIccTransform);
    970         } else {
    971             ret = FALSE;
    972         }
    973     }
    974     if (pBitmap->HasAlpha() && ret) {
    975         pBitmap->LoadChannel(FXDIB_Alpha, 0xff);
    976     }
    977     DeleteObject(hbmp);
    978     DeleteObject(hDCMemory);
    979     return ret;
    980 }
    981 FX_BOOL CGdiDisplayDriver::SetDIBits(const CFX_DIBSource* pSource, FX_DWORD color, const FX_RECT* pSrcRect, int left, int top, int blend_type,
    982                                      int alpha_flag, void* pIccTransform)
    983 {
    984     ASSERT(blend_type == FXDIB_BLEND_NORMAL);
    985     if (pSource->IsAlphaMask()) {
    986         int width = pSource->GetWidth(), height = pSource->GetHeight();
    987         int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(color);
    988         FX_BOOL bGDI = pSource->GetBPP() == 1 && alpha == 255;
    989         if (!bGDI) {
    990             CFX_DIBitmap background;
    991             if (!background.Create(width, height, FXDIB_Rgb32) ||
    992                     !GetDIBits(&background, left, top, NULL) ||
    993                     !background.CompositeMask(0, 0, width, height, pSource, color, 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
    994                 return FALSE;
    995             }
    996             FX_RECT src_rect(0, 0, width, height);
    997             return SetDIBits(&background, 0, &src_rect, left, top, FXDIB_BLEND_NORMAL, 0, NULL);
    998         }
    999         FX_RECT clip_rect(left, top, left + pSrcRect->Width(), top + pSrcRect->Height());
   1000         return StretchDIBits(pSource, color, left - pSrcRect->left, top - pSrcRect->top, width, height,
   1001                              &clip_rect, 0, alpha_flag, pIccTransform, FXDIB_BLEND_NORMAL);
   1002     } else {
   1003         int width = pSrcRect->Width(), height = pSrcRect->Height();
   1004         if (pSource->HasAlpha()) {
   1005             CFX_DIBitmap bitmap;
   1006             if (!bitmap.Create(width, height, FXDIB_Rgb) ||
   1007                     !GetDIBits(&bitmap, left, top, NULL) ||
   1008                     !bitmap.CompositeBitmap(0, 0, width, height, pSource, pSrcRect->left, pSrcRect->top, FXDIB_BLEND_NORMAL, NULL, FALSE, pIccTransform)) {
   1009                 return FALSE;
   1010             }
   1011             FX_RECT src_rect(0, 0, width, height);
   1012             return SetDIBits(&bitmap, 0, &src_rect, left, top, FXDIB_BLEND_NORMAL, 0, NULL);
   1013         }
   1014         CFX_DIBExtractor temp(pSource);
   1015         CFX_DIBitmap* pBitmap = temp;
   1016         if (pBitmap) {
   1017             return GDI_SetDIBits(pBitmap, pSrcRect, left, top, pIccTransform);
   1018         }
   1019     }
   1020     return FALSE;
   1021 }
   1022 FX_BOOL CGdiDisplayDriver::UseFoxitStretchEngine(const CFX_DIBSource* pSource, FX_DWORD color, int dest_left, int dest_top,
   1023         int dest_width, int dest_height, const FX_RECT* pClipRect, int render_flags,
   1024         int alpha_flag, void* pIccTransform, int blend_type)
   1025 {
   1026     FX_RECT bitmap_clip = *pClipRect;
   1027     if (dest_width < 0) {
   1028         dest_left += dest_width;
   1029     }
   1030     if (dest_height < 0) {
   1031         dest_top += dest_height;
   1032     }
   1033     bitmap_clip.Offset(-dest_left, -dest_top);
   1034     CFX_DIBitmap* pStretched = pSource->StretchTo(dest_width, dest_height, render_flags, &bitmap_clip);
   1035     if (pStretched == NULL) {
   1036         return TRUE;
   1037     }
   1038     FX_RECT src_rect(0, 0, pStretched->GetWidth(), pStretched->GetHeight());
   1039     FX_BOOL ret = SetDIBits(pStretched, color, &src_rect, pClipRect->left, pClipRect->top, FXDIB_BLEND_NORMAL, alpha_flag, pIccTransform);
   1040     delete pStretched;
   1041     return ret;
   1042 }
   1043 FX_BOOL CGdiDisplayDriver::StretchDIBits(const CFX_DIBSource* pSource, FX_DWORD color, int dest_left, int dest_top,
   1044         int dest_width, int dest_height, const FX_RECT* pClipRect, FX_DWORD flags,
   1045         int alpha_flag, void* pIccTransform, int blend_type)
   1046 {
   1047     ASSERT(pSource != NULL && pClipRect != NULL);
   1048     if (flags || dest_width > 10000 || dest_width < -10000 || dest_height > 10000 || dest_height < -10000)
   1049         return UseFoxitStretchEngine(pSource, color, dest_left, dest_top, dest_width, dest_height,
   1050                                      pClipRect, flags, alpha_flag, pIccTransform, blend_type);
   1051     if (pSource->IsAlphaMask()) {
   1052         FX_RECT image_rect;
   1053         image_rect.left = dest_width > 0 ? dest_left : dest_left + dest_width;
   1054         image_rect.right = dest_width > 0 ? dest_left + dest_width : dest_left;
   1055         image_rect.top = dest_height > 0 ? dest_top : dest_top + dest_height;
   1056         image_rect.bottom = dest_height > 0 ? dest_top + dest_height : dest_top;
   1057         FX_RECT clip_rect = image_rect;
   1058         clip_rect.Intersect(*pClipRect);
   1059         clip_rect.Offset(-image_rect.left, -image_rect.top);
   1060         int clip_width = clip_rect.Width(), clip_height = clip_rect.Height();
   1061         CFX_DIBitmap* pStretched = pSource->StretchTo(dest_width, dest_height, flags, &clip_rect);
   1062         if (pStretched == NULL) {
   1063             return TRUE;
   1064         }
   1065         CFX_DIBitmap background;
   1066         if (!background.Create(clip_width, clip_height, FXDIB_Rgb32) ||
   1067                 !GetDIBits(&background, image_rect.left + clip_rect.left, image_rect.top + clip_rect.top, NULL) ||
   1068                 !background.CompositeMask(0, 0, clip_width, clip_height, pStretched, color, 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
   1069             delete pStretched;
   1070             return FALSE;
   1071         }
   1072         FX_RECT src_rect(0, 0, clip_width, clip_height);
   1073         FX_BOOL ret = SetDIBits(&background, 0, &src_rect, image_rect.left + clip_rect.left, image_rect.top + clip_rect.top, FXDIB_BLEND_NORMAL, 0, NULL);
   1074         delete pStretched;
   1075         return ret;
   1076     } else {
   1077         if (pSource->HasAlpha()) {
   1078             CWin32Platform* pPlatform = (CWin32Platform*)CFX_GEModule::Get()->GetPlatformData();
   1079             if (pPlatform->m_GdiplusExt.IsAvailable() && pIccTransform == NULL && !pSource->IsCmykImage()) {
   1080                 CFX_DIBExtractor temp(pSource);
   1081                 CFX_DIBitmap* pBitmap = temp;
   1082                 if (pBitmap == NULL) {
   1083                     return FALSE;
   1084                 }
   1085                 return pPlatform->m_GdiplusExt.StretchDIBits(m_hDC, pBitmap, dest_left, dest_top, dest_width, dest_height, pClipRect, flags);
   1086             }
   1087             return UseFoxitStretchEngine(pSource, color, dest_left, dest_top, dest_width, dest_height,
   1088                                          pClipRect, flags, alpha_flag, pIccTransform, blend_type);
   1089         }
   1090         CFX_DIBExtractor temp(pSource);
   1091         CFX_DIBitmap* pBitmap = temp;
   1092         if (pBitmap) {
   1093             return GDI_StretchDIBits(pBitmap, dest_left, dest_top, dest_width, dest_height, flags, pIccTransform);
   1094         }
   1095     }
   1096     return FALSE;
   1097 }
   1098 #define GET_PS_FEATURESETTING        4121
   1099 #define FEATURESETTING_PSLEVEL       2
   1100 int GetPSLevel(HDC hDC)
   1101 {
   1102     int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY);
   1103     if (device_type != DT_RASPRINTER) {
   1104         return 0;
   1105     }
   1106     FX_DWORD esc = GET_PS_FEATURESETTING;
   1107     if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) {
   1108         int param = FEATURESETTING_PSLEVEL;
   1109         if (ExtEscape(hDC, GET_PS_FEATURESETTING, sizeof(int), (char*)&param, sizeof(int), (char*)&param) > 0) {
   1110             return param;
   1111         }
   1112     }
   1113     esc = POSTSCRIPT_IDENTIFY;
   1114     if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL) == 0) {
   1115         esc = POSTSCRIPT_DATA;
   1116         if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) {
   1117             return 2;
   1118         }
   1119         return 0;
   1120     }
   1121     esc = PSIDENT_GDICENTRIC;
   1122     if (ExtEscape(hDC, POSTSCRIPT_IDENTIFY, sizeof(FX_DWORD), (char*)&esc, 0, NULL) <= 0) {
   1123         return 2;
   1124     }
   1125     esc = GET_PS_FEATURESETTING;
   1126     if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof esc, (char*)&esc, 0, NULL)) {
   1127         int param = FEATURESETTING_PSLEVEL;
   1128         if (ExtEscape(hDC, GET_PS_FEATURESETTING, sizeof(int), (char*)&param, sizeof(int), (char*)&param) > 0) {
   1129             return param;
   1130         }
   1131     }
   1132     return 2;
   1133 }
   1134 int CFX_WindowsDevice::m_psLevel = 2;
   1135 CFX_WindowsDevice::CFX_WindowsDevice(HDC hDC, FX_BOOL bCmykOutput, FX_BOOL bForcePSOutput, int psLevel)
   1136 {
   1137     m_bForcePSOutput = bForcePSOutput;
   1138     m_psLevel = psLevel;
   1139     if (bForcePSOutput) {
   1140         IFX_RenderDeviceDriver* pDriver = new CPSPrinterDriver;
   1141         ((CPSPrinterDriver*)pDriver)->Init(hDC, psLevel, bCmykOutput);
   1142         SetDeviceDriver(pDriver);
   1143         return;
   1144     }
   1145     SetDeviceDriver(CreateDriver(hDC, bCmykOutput));
   1146 }
   1147 HDC CFX_WindowsDevice::GetDC() const
   1148 {
   1149     IFX_RenderDeviceDriver *pRDD = GetDeviceDriver();
   1150     if (!pRDD) {
   1151         return NULL;
   1152     }
   1153     return (HDC)pRDD->GetPlatformSurface();
   1154 }
   1155 IFX_RenderDeviceDriver* CFX_WindowsDevice::CreateDriver(HDC hDC, FX_BOOL bCmykOutput)
   1156 {
   1157     int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY);
   1158     int obj_type = ::GetObjectType(hDC);
   1159     int device_class;
   1160     if (device_type == DT_RASPRINTER || device_type == DT_PLOTTER || obj_type == OBJ_ENHMETADC) {
   1161         device_class = FXDC_PRINTER;
   1162     } else {
   1163         device_class = FXDC_DISPLAY;
   1164     }
   1165     if (device_class == FXDC_PRINTER) {
   1166         return new CGdiPrinterDriver(hDC);
   1167     }
   1168     return new CGdiDisplayDriver(hDC);
   1169 }
   1170 CFX_WinBitmapDevice::CFX_WinBitmapDevice(int width, int height, FXDIB_Format format)
   1171 {
   1172     BITMAPINFOHEADER bmih;
   1173     FXSYS_memset32(&bmih, 0, sizeof (BITMAPINFOHEADER));
   1174     bmih.biSize = sizeof(BITMAPINFOHEADER);
   1175     bmih.biBitCount = format & 0xff;
   1176     bmih.biHeight = -height;
   1177     bmih.biPlanes = 1;
   1178     bmih.biWidth = width;
   1179     FX_LPBYTE pBuffer;
   1180     m_hBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (FX_LPVOID*)&pBuffer, NULL, 0);
   1181     if (m_hBitmap == NULL) {
   1182         return;
   1183     }
   1184     CFX_DIBitmap* pBitmap = new CFX_DIBitmap;
   1185     pBitmap->Create(width, height, format, pBuffer);
   1186     SetBitmap(pBitmap);
   1187     m_hDC = ::CreateCompatibleDC(NULL);
   1188     m_hOldBitmap = (HBITMAP)SelectObject(m_hDC, m_hBitmap);
   1189     IFX_RenderDeviceDriver* pDriver = new CGdiDisplayDriver(m_hDC);
   1190     SetDeviceDriver(pDriver);
   1191 }
   1192 CFX_WinBitmapDevice::~CFX_WinBitmapDevice()
   1193 {
   1194     if (m_hDC) {
   1195         SelectObject(m_hDC, m_hOldBitmap);
   1196         DeleteDC(m_hDC);
   1197     }
   1198     if (m_hBitmap) {
   1199         DeleteObject(m_hBitmap);
   1200     }
   1201     delete GetBitmap();
   1202 }
   1203 #endif
   1204