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