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 "dwrite_int.h" 11 #include <dwrite.h> 12 typedef HRESULT (__stdcall *FuncType_DWriteCreateFactory)(__in DWRITE_FACTORY_TYPE, __in REFIID, __out IUnknown **); 13 template <typename InterfaceType> 14 inline void SafeRelease(InterfaceType** currentObject) 15 { 16 if (*currentObject != NULL) { 17 (*currentObject)->Release(); 18 *currentObject = NULL; 19 } 20 } 21 template <typename InterfaceType> 22 inline InterfaceType* SafeAcquire(InterfaceType* newObject) 23 { 24 if (newObject != NULL) { 25 newObject->AddRef(); 26 } 27 return newObject; 28 } 29 class CDwFontFileStream FX_FINAL : public IDWriteFontFileStream 30 { 31 public: 32 explicit CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize); 33 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); 34 virtual ULONG STDMETHODCALLTYPE AddRef(); 35 virtual ULONG STDMETHODCALLTYPE Release(); 36 virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void** fragmentContext); 37 virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); 38 virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); 39 virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); 40 bool IsInitialized() 41 { 42 return resourcePtr_ != NULL; 43 } 44 private: 45 ULONG refCount_; 46 void const* resourcePtr_; 47 DWORD resourceSize_; 48 }; 49 class CDwFontFileLoader FX_FINAL : public IDWriteFontFileLoader 50 { 51 public: 52 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject); 53 virtual ULONG STDMETHODCALLTYPE AddRef(); 54 virtual ULONG STDMETHODCALLTYPE Release(); 55 virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize, OUT IDWriteFontFileStream** fontFileStream); 56 57 static IDWriteFontFileLoader* GetLoader() 58 { 59 if (instance_ == NULL) { 60 instance_ = new CDwFontFileLoader(); 61 } 62 return instance_; 63 } 64 static bool IsLoaderInitialized() 65 { 66 return instance_ != NULL; 67 } 68 private: 69 CDwFontFileLoader(); 70 ULONG refCount_; 71 static IDWriteFontFileLoader* instance_; 72 }; 73 class CDwFontContext 74 { 75 public: 76 CDwFontContext(IDWriteFactory* dwriteFactory); 77 ~CDwFontContext(); 78 HRESULT Initialize(); 79 private: 80 CDwFontContext(CDwFontContext const&); 81 void operator=(CDwFontContext const&); 82 HRESULT hr_; 83 IDWriteFactory* dwriteFactory_; 84 }; 85 class CDwGdiTextRenderer 86 { 87 public: 88 CDwGdiTextRenderer( 89 CFX_DIBitmap* pBitmap, 90 IDWriteBitmapRenderTarget* bitmapRenderTarget, 91 IDWriteRenderingParams* renderingParams 92 ); 93 CDwGdiTextRenderer::~CDwGdiTextRenderer(); 94 HRESULT STDMETHODCALLTYPE DrawGlyphRun( 95 const FX_RECT& text_bbox, 96 __in_opt CFX_ClipRgn* pClipRgn, 97 __in_opt DWRITE_MATRIX const* pMatrix, 98 FLOAT baselineOriginX, 99 FLOAT baselineOriginY, 100 DWRITE_MEASURING_MODE measuringMode, 101 __in DWRITE_GLYPH_RUN const* glyphRun, 102 const COLORREF& textColor 103 ); 104 private: 105 CFX_DIBitmap* pBitmap_; 106 IDWriteBitmapRenderTarget* pRenderTarget_; 107 IDWriteRenderingParams* pRenderingParams_; 108 }; 109 CDWriteExt::CDWriteExt() 110 { 111 m_hModule = NULL; 112 m_pDWriteFactory = NULL; 113 m_pDwFontContext = NULL; 114 m_pDwTextRenderer = NULL; 115 } 116 void CDWriteExt::Load() 117 { 118 } 119 void CDWriteExt::Unload() 120 { 121 if (m_pDwFontContext) { 122 delete (CDwFontContext*)m_pDwFontContext; 123 m_pDwFontContext = NULL; 124 } 125 SafeRelease((IDWriteFactory**)&m_pDWriteFactory); 126 } 127 CDWriteExt::~CDWriteExt() 128 { 129 Unload(); 130 } 131 LPVOID CDWriteExt::DwCreateFontFaceFromStream(FX_LPBYTE pData, FX_DWORD size, int simulation_style) 132 { 133 IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory; 134 IDWriteFontFile* pDwFontFile = NULL; 135 IDWriteFontFace* pDwFontFace = NULL; 136 BOOL isSupportedFontType = FALSE; 137 DWRITE_FONT_FILE_TYPE fontFileType; 138 DWRITE_FONT_FACE_TYPE fontFaceType; 139 UINT32 numberOfFaces; 140 DWRITE_FONT_SIMULATIONS fontStyle = (DWRITE_FONT_SIMULATIONS)(simulation_style & 3); 141 HRESULT hr = S_OK; 142 hr = pDwFactory->CreateCustomFontFileReference( 143 (void const*)pData, 144 (UINT32)size, 145 CDwFontFileLoader::GetLoader(), 146 &pDwFontFile 147 ); 148 if (FAILED(hr)) { 149 goto failed; 150 } 151 hr = pDwFontFile->Analyze( 152 &isSupportedFontType, 153 &fontFileType, 154 &fontFaceType, 155 &numberOfFaces 156 ); 157 if (FAILED(hr) || !isSupportedFontType || fontFaceType == DWRITE_FONT_FACE_TYPE_UNKNOWN) { 158 goto failed; 159 } 160 hr = pDwFactory->CreateFontFace( 161 fontFaceType, 162 1, 163 &pDwFontFile, 164 0, 165 fontStyle, 166 &pDwFontFace 167 ); 168 if (FAILED(hr)) { 169 goto failed; 170 } 171 SafeRelease(&pDwFontFile); 172 return pDwFontFace; 173 failed: 174 SafeRelease(&pDwFontFile); 175 return NULL; 176 } 177 FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap, void** renderTarget) 178 { 179 if (pBitmap->GetFormat() > FXDIB_Argb) { 180 return FALSE; 181 } 182 IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory; 183 IDWriteGdiInterop* pGdiInterop = NULL; 184 IDWriteBitmapRenderTarget* pBitmapRenderTarget = NULL; 185 IDWriteRenderingParams* pRenderingParams = NULL; 186 HRESULT hr = S_OK; 187 hr = pDwFactory->GetGdiInterop(&pGdiInterop); 188 if (FAILED(hr)) { 189 goto failed; 190 } 191 hr = pGdiInterop->CreateBitmapRenderTarget(NULL, pBitmap->GetWidth(), pBitmap->GetHeight(), 192 &pBitmapRenderTarget); 193 if (FAILED(hr)) { 194 goto failed; 195 } 196 hr = pDwFactory->CreateCustomRenderingParams( 197 1.0f, 198 0.0f, 199 1.0f, 200 DWRITE_PIXEL_GEOMETRY_RGB, 201 DWRITE_RENDERING_MODE_DEFAULT, 202 &pRenderingParams 203 ); 204 if (FAILED(hr)) { 205 goto failed; 206 } 207 hr = pBitmapRenderTarget->SetPixelsPerDip(1.0f); 208 if (FAILED(hr)) { 209 goto failed; 210 } 211 *(CDwGdiTextRenderer**)renderTarget = new CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams); 212 SafeRelease(&pGdiInterop); 213 SafeRelease(&pBitmapRenderTarget); 214 SafeRelease(&pRenderingParams); 215 return TRUE; 216 failed: 217 SafeRelease(&pGdiInterop); 218 SafeRelease(&pBitmapRenderTarget); 219 SafeRelease(&pRenderingParams); 220 return FALSE; 221 } 222 FX_BOOL CDWriteExt::DwRendingString(void* renderTarget, CFX_ClipRgn* pClipRgn, FX_RECT& stringRect, CFX_AffineMatrix* pMatrix, 223 void *font, FX_FLOAT font_size, FX_ARGB text_color, 224 int glyph_count, unsigned short* glyph_indices, 225 FX_FLOAT baselineOriginX, FX_FLOAT baselineOriginY, 226 void* glyph_offsets, 227 FX_FLOAT* glyph_advances) 228 { 229 if (renderTarget == NULL) { 230 return TRUE; 231 } 232 CDwGdiTextRenderer* pTextRenderer = (CDwGdiTextRenderer*)renderTarget; 233 DWRITE_MATRIX transform; 234 DWRITE_GLYPH_RUN glyphRun; 235 HRESULT hr = S_OK; 236 if (pMatrix) { 237 transform.m11 = pMatrix->a; 238 transform.m12 = pMatrix->b; 239 transform.m21 = pMatrix->c; 240 transform.m22 = pMatrix->d; 241 transform.dx = pMatrix->e; 242 transform.dy = pMatrix->f; 243 } 244 glyphRun.fontFace = (IDWriteFontFace*)font; 245 glyphRun.fontEmSize = font_size; 246 glyphRun.glyphCount = glyph_count; 247 glyphRun.glyphIndices = glyph_indices; 248 glyphRun.glyphAdvances = glyph_advances; 249 glyphRun.glyphOffsets = (DWRITE_GLYPH_OFFSET*)glyph_offsets; 250 glyphRun.isSideways = FALSE; 251 glyphRun.bidiLevel = 0; 252 hr = pTextRenderer->DrawGlyphRun( 253 stringRect, 254 pClipRgn, 255 pMatrix ? &transform : NULL, 256 baselineOriginX, baselineOriginY, 257 DWRITE_MEASURING_MODE_NATURAL, 258 &glyphRun, 259 RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color)) 260 ); 261 return SUCCEEDED(hr) ? TRUE : FALSE; 262 } 263 void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget) 264 { 265 if (renderTarget) { 266 delete (CDwGdiTextRenderer*)renderTarget; 267 } 268 } 269 void CDWriteExt::DwDeleteFont(void* pFont) 270 { 271 if (pFont) { 272 SafeRelease((IDWriteFontFace**)&pFont); 273 } 274 } 275 CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize) 276 { 277 refCount_ = 0; 278 resourcePtr_ = fontFileReferenceKey; 279 resourceSize_ = fontFileReferenceKeySize; 280 } 281 HRESULT STDMETHODCALLTYPE CDwFontFileStream::QueryInterface(REFIID iid, void** ppvObject) 282 { 283 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { 284 *ppvObject = this; 285 AddRef(); 286 return S_OK; 287 } else { 288 *ppvObject = NULL; 289 return E_NOINTERFACE; 290 } 291 } 292 ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef() 293 { 294 return InterlockedIncrement((long*)(&refCount_)); 295 } 296 ULONG STDMETHODCALLTYPE CDwFontFileStream::Release() 297 { 298 ULONG newCount = InterlockedDecrement((long*)(&refCount_)); 299 if (newCount == 0) { 300 delete this; 301 } 302 return newCount; 303 } 304 HRESULT STDMETHODCALLTYPE CDwFontFileStream::ReadFileFragment( 305 void const** fragmentStart, 306 UINT64 fileOffset, 307 UINT64 fragmentSize, 308 OUT void** fragmentContext 309 ) 310 { 311 if (fileOffset <= resourceSize_ && 312 fragmentSize <= resourceSize_ - fileOffset) { 313 *fragmentStart = static_cast<FX_BYTE const*>(resourcePtr_) + static_cast<size_t>(fileOffset); 314 *fragmentContext = NULL; 315 return S_OK; 316 } else { 317 *fragmentStart = NULL; 318 *fragmentContext = NULL; 319 return E_FAIL; 320 } 321 } 322 void STDMETHODCALLTYPE CDwFontFileStream::ReleaseFileFragment(void* fragmentContext) 323 { 324 } 325 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize) 326 { 327 *fileSize = resourceSize_; 328 return S_OK; 329 } 330 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime) 331 { 332 *lastWriteTime = 0; 333 return E_NOTIMPL; 334 } 335 IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL; 336 CDwFontFileLoader::CDwFontFileLoader() : 337 refCount_(0) 338 { 339 } 340 HRESULT STDMETHODCALLTYPE CDwFontFileLoader::QueryInterface(REFIID iid, void** ppvObject) 341 { 342 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { 343 *ppvObject = this; 344 AddRef(); 345 return S_OK; 346 } else { 347 *ppvObject = NULL; 348 return E_NOINTERFACE; 349 } 350 } 351 ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef() 352 { 353 return InterlockedIncrement((long*)(&refCount_)); 354 } 355 ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release() 356 { 357 ULONG newCount = InterlockedDecrement((long*)(&refCount_)); 358 if (newCount == 0) { 359 instance_ = NULL; 360 delete this; 361 } 362 return newCount; 363 } 364 HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey( 365 void const* fontFileReferenceKey, 366 UINT32 fontFileReferenceKeySize, 367 OUT IDWriteFontFileStream** fontFileStream 368 ) 369 { 370 *fontFileStream = NULL; 371 CDwFontFileStream* stream = new CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize); 372 if (!stream->IsInitialized()) { 373 delete stream; 374 return E_FAIL; 375 } 376 *fontFileStream = SafeAcquire(stream); 377 return S_OK; 378 } 379 CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) : 380 hr_(S_FALSE), 381 dwriteFactory_(SafeAcquire(dwriteFactory)) 382 { 383 } 384 CDwFontContext::~CDwFontContext() 385 { 386 if(dwriteFactory_ && hr_ == S_OK) { 387 dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader()); 388 } 389 SafeRelease(&dwriteFactory_); 390 } 391 HRESULT CDwFontContext::Initialize() 392 { 393 if (hr_ == S_FALSE) { 394 return hr_ = dwriteFactory_->RegisterFontFileLoader(CDwFontFileLoader::GetLoader()); 395 } 396 return hr_; 397 } 398 CDwGdiTextRenderer::CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, IDWriteBitmapRenderTarget* bitmapRenderTarget, IDWriteRenderingParams* renderingParams): 399 pBitmap_(pBitmap), 400 pRenderTarget_(SafeAcquire(bitmapRenderTarget)), 401 pRenderingParams_(SafeAcquire(renderingParams)) 402 { 403 } 404 CDwGdiTextRenderer::~CDwGdiTextRenderer() 405 { 406 SafeRelease(&pRenderTarget_); 407 SafeRelease(&pRenderingParams_); 408 } 409 STDMETHODIMP CDwGdiTextRenderer::DrawGlyphRun( 410 const FX_RECT& text_bbox, 411 __in_opt CFX_ClipRgn* pClipRgn, 412 __in_opt DWRITE_MATRIX const* pMatrix, 413 FLOAT baselineOriginX, 414 FLOAT baselineOriginY, 415 DWRITE_MEASURING_MODE measuringMode, 416 __in DWRITE_GLYPH_RUN const* glyphRun, 417 const COLORREF& textColor 418 ) 419 { 420 HRESULT hr = S_OK; 421 if (pMatrix) { 422 hr = pRenderTarget_->SetCurrentTransform(pMatrix); 423 if (FAILED(hr)) { 424 return hr; 425 } 426 } 427 HDC hDC = pRenderTarget_->GetMemoryDC(); 428 HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hDC, OBJ_BITMAP); 429 BITMAP bitmap; 430 GetObject(hBitmap, sizeof bitmap, &bitmap); 431 CFX_DIBitmap dib; 432 dib.Create( 433 bitmap.bmWidth, 434 bitmap.bmHeight, 435 bitmap.bmBitsPixel == 24 ? FXDIB_Rgb : FXDIB_Rgb32, 436 (FX_LPBYTE)bitmap.bmBits 437 ); 438 dib.CompositeBitmap( 439 text_bbox.left, 440 text_bbox.top, 441 text_bbox.Width(), 442 text_bbox.Height(), 443 pBitmap_, 444 text_bbox.left, 445 text_bbox.top, 446 FXDIB_BLEND_NORMAL, 447 NULL 448 ); 449 hr = pRenderTarget_->DrawGlyphRun( 450 baselineOriginX, 451 baselineOriginY, 452 measuringMode, 453 glyphRun, 454 pRenderingParams_, 455 textColor 456 ); 457 if (FAILED(hr)) { 458 return hr; 459 } 460 pBitmap_->CompositeBitmap( 461 text_bbox.left, 462 text_bbox.top, 463 text_bbox.Width(), 464 text_bbox.Height(), 465 &dib, 466 text_bbox.left, 467 text_bbox.top, 468 FXDIB_BLEND_NORMAL, 469 pClipRgn 470 ); 471 return hr; 472 } 473 #endif 474