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 "core/include/fxge/fx_ge.h" 8 9 CFX_RenderDevice::CFX_RenderDevice() { 10 m_pDeviceDriver = NULL; 11 m_pBitmap = NULL; 12 } 13 CFX_RenderDevice::~CFX_RenderDevice() { 14 delete m_pDeviceDriver; 15 } 16 void CFX_RenderDevice::SetDeviceDriver(IFX_RenderDeviceDriver* pDriver) { 17 delete m_pDeviceDriver; 18 m_pDeviceDriver = pDriver; 19 InitDeviceInfo(); 20 } 21 void CFX_RenderDevice::InitDeviceInfo() { 22 m_Width = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH); 23 m_Height = m_pDeviceDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT); 24 m_bpp = m_pDeviceDriver->GetDeviceCaps(FXDC_BITS_PIXEL); 25 m_RenderCaps = m_pDeviceDriver->GetDeviceCaps(FXDC_RENDER_CAPS); 26 m_DeviceClass = m_pDeviceDriver->GetDeviceCaps(FXDC_DEVICE_CLASS); 27 if (!m_pDeviceDriver->GetClipBox(&m_ClipBox)) { 28 m_ClipBox.left = 0; 29 m_ClipBox.top = 0; 30 m_ClipBox.right = m_Width; 31 m_ClipBox.bottom = m_Height; 32 } 33 } 34 FX_BOOL CFX_RenderDevice::StartRendering() { 35 return m_pDeviceDriver->StartRendering(); 36 } 37 void CFX_RenderDevice::EndRendering() { 38 m_pDeviceDriver->EndRendering(); 39 } 40 void CFX_RenderDevice::SaveState() { 41 m_pDeviceDriver->SaveState(); 42 } 43 void CFX_RenderDevice::RestoreState(FX_BOOL bKeepSaved) { 44 m_pDeviceDriver->RestoreState(bKeepSaved); 45 UpdateClipBox(); 46 } 47 int CFX_RenderDevice::GetDeviceCaps(int caps_id) const { 48 return m_pDeviceDriver->GetDeviceCaps(caps_id); 49 } 50 CFX_Matrix CFX_RenderDevice::GetCTM() const { 51 return m_pDeviceDriver->GetCTM(); 52 } 53 FX_BOOL CFX_RenderDevice::CreateCompatibleBitmap(CFX_DIBitmap* pDIB, 54 int width, 55 int height) const { 56 if (m_RenderCaps & FXRC_CMYK_OUTPUT) { 57 return pDIB->Create(width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT 58 ? FXDIB_Cmyka 59 : FXDIB_Cmyk); 60 } 61 if (m_RenderCaps & FXRC_BYTEMASK_OUTPUT) { 62 return pDIB->Create(width, height, FXDIB_8bppMask); 63 } 64 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ 65 return pDIB->Create(width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT 66 ? FXDIB_Argb 67 : FXDIB_Rgb32); 68 #else 69 return pDIB->Create( 70 width, height, m_RenderCaps & FXRC_ALPHA_OUTPUT ? FXDIB_Argb : FXDIB_Rgb); 71 #endif 72 } 73 FX_BOOL CFX_RenderDevice::SetClip_PathFill(const CFX_PathData* pPathData, 74 const CFX_Matrix* pObject2Device, 75 int fill_mode) { 76 if (!m_pDeviceDriver->SetClip_PathFill(pPathData, pObject2Device, 77 fill_mode)) { 78 return FALSE; 79 } 80 UpdateClipBox(); 81 return TRUE; 82 } 83 FX_BOOL CFX_RenderDevice::SetClip_PathStroke( 84 const CFX_PathData* pPathData, 85 const CFX_Matrix* pObject2Device, 86 const CFX_GraphStateData* pGraphState) { 87 if (!m_pDeviceDriver->SetClip_PathStroke(pPathData, pObject2Device, 88 pGraphState)) { 89 return FALSE; 90 } 91 UpdateClipBox(); 92 return TRUE; 93 } 94 FX_BOOL CFX_RenderDevice::SetClip_Rect(const FX_RECT* pRect) { 95 CFX_PathData path; 96 path.AppendRect((FX_FLOAT)(pRect->left), (FX_FLOAT)(pRect->bottom), 97 (FX_FLOAT)(pRect->right), (FX_FLOAT)(pRect->top)); 98 if (!SetClip_PathFill(&path, NULL, FXFILL_WINDING)) { 99 return FALSE; 100 } 101 UpdateClipBox(); 102 return TRUE; 103 } 104 void CFX_RenderDevice::UpdateClipBox() { 105 if (m_pDeviceDriver->GetClipBox(&m_ClipBox)) { 106 return; 107 } 108 m_ClipBox.left = 0; 109 m_ClipBox.top = 0; 110 m_ClipBox.right = m_Width; 111 m_ClipBox.bottom = m_Height; 112 } 113 FX_BOOL CFX_RenderDevice::DrawPath(const CFX_PathData* pPathData, 114 const CFX_Matrix* pObject2Device, 115 const CFX_GraphStateData* pGraphState, 116 FX_DWORD fill_color, 117 FX_DWORD stroke_color, 118 int fill_mode, 119 int alpha_flag, 120 void* pIccTransform, 121 int blend_type) { 122 uint8_t fill_alpha, stroke_alpha; 123 if (FXGETFLAG_COLORTYPE(alpha_flag)) { 124 fill_alpha = FXGETFLAG_ALPHA_FILL(alpha_flag); 125 stroke_alpha = FXGETFLAG_ALPHA_STROKE(alpha_flag); 126 } else { 127 fill_alpha = FXARGB_A(fill_color); 128 stroke_alpha = FXARGB_A(stroke_color); 129 } 130 if ((fill_mode & 3) == 0) { 131 fill_alpha = 0; 132 } 133 if (!pGraphState) { 134 stroke_alpha = 0; 135 } 136 if (stroke_alpha == 0 && pPathData->GetPointCount() == 2) { 137 FX_PATHPOINT* pPoints = pPathData->GetPoints(); 138 FX_FLOAT x1, x2, y1, y2; 139 if (pObject2Device) { 140 pObject2Device->Transform(pPoints[0].m_PointX, pPoints[0].m_PointY, x1, 141 y1); 142 pObject2Device->Transform(pPoints[1].m_PointX, pPoints[1].m_PointY, x2, 143 y2); 144 } else { 145 x1 = pPoints[0].m_PointX; 146 y1 = pPoints[0].m_PointY; 147 x2 = pPoints[1].m_PointX; 148 y2 = pPoints[1].m_PointY; 149 } 150 DrawCosmeticLine(x1, y1, x2, y2, fill_color, fill_mode, alpha_flag, 151 pIccTransform, blend_type); 152 return TRUE; 153 } 154 if ((pPathData->GetPointCount() == 5 || pPathData->GetPointCount() == 4) && 155 stroke_alpha == 0) { 156 CFX_FloatRect rect_f; 157 if (!(fill_mode & FXFILL_RECT_AA) && 158 pPathData->IsRect(pObject2Device, &rect_f)) { 159 FX_RECT rect_i = rect_f.GetOutterRect(); 160 int width = (int)FXSYS_ceil(rect_f.right - rect_f.left); 161 if (width < 1) { 162 width = 1; 163 if (rect_i.left == rect_i.right) { 164 rect_i.right++; 165 } 166 } 167 int height = (int)FXSYS_ceil(rect_f.top - rect_f.bottom); 168 if (height < 1) { 169 height = 1; 170 if (rect_i.bottom == rect_i.top) { 171 rect_i.bottom++; 172 } 173 } 174 if (rect_i.Width() >= width + 1) { 175 if (rect_f.left - (FX_FLOAT)(rect_i.left) > 176 (FX_FLOAT)(rect_i.right) - rect_f.right) { 177 rect_i.left++; 178 } else { 179 rect_i.right--; 180 } 181 } 182 if (rect_i.Height() >= height + 1) { 183 if (rect_f.top - (FX_FLOAT)(rect_i.top) > 184 (FX_FLOAT)(rect_i.bottom) - rect_f.bottom) { 185 rect_i.top++; 186 } else { 187 rect_i.bottom--; 188 } 189 } 190 if (FillRect(&rect_i, fill_color, alpha_flag, pIccTransform, 191 blend_type)) { 192 return TRUE; 193 } 194 } 195 } 196 if ((fill_mode & 3) && stroke_alpha == 0 && !(fill_mode & FX_FILL_STROKE) && 197 !(fill_mode & FX_FILL_TEXT_MODE)) { 198 CFX_PathData newPath; 199 FX_BOOL bThin = FALSE; 200 if (pPathData->GetZeroAreaPath(newPath, (CFX_Matrix*)pObject2Device, bThin, 201 m_pDeviceDriver->GetDriverType())) { 202 CFX_GraphStateData graphState; 203 graphState.m_LineWidth = 0.0f; 204 FX_DWORD strokecolor = fill_color; 205 if (bThin) { 206 if (FXGETFLAG_COLORTYPE(alpha_flag)) { 207 FXSETFLAG_ALPHA_STROKE(alpha_flag, fill_alpha >> 2); 208 } else { 209 strokecolor = 210 (((fill_alpha >> 2) << 24) | (strokecolor & 0x00ffffff)); 211 } 212 } 213 CFX_Matrix* pMatrix = NULL; 214 if (pObject2Device && !pObject2Device->IsIdentity()) { 215 pMatrix = (CFX_Matrix*)pObject2Device; 216 } 217 int smooth_path = FX_ZEROAREA_FILL; 218 if (fill_mode & FXFILL_NOPATHSMOOTH) { 219 smooth_path |= FXFILL_NOPATHSMOOTH; 220 } 221 m_pDeviceDriver->DrawPath(&newPath, pMatrix, &graphState, 0, strokecolor, 222 smooth_path, alpha_flag, pIccTransform, 223 blend_type); 224 } 225 } 226 if ((fill_mode & 3) && fill_alpha && stroke_alpha < 0xff && 227 (fill_mode & FX_FILL_STROKE)) { 228 if (!(m_RenderCaps & FXRC_GET_BITS)) { 229 return FALSE; 230 } 231 CFX_FloatRect bbox; 232 if (pGraphState) { 233 bbox = pPathData->GetBoundingBox(pGraphState->m_LineWidth, 234 pGraphState->m_MiterLimit); 235 } else { 236 bbox = pPathData->GetBoundingBox(); 237 } 238 if (pObject2Device) { 239 bbox.Transform(pObject2Device); 240 } 241 CFX_Matrix ctm = GetCTM(); 242 FX_FLOAT fScaleX = FXSYS_fabs(ctm.a); 243 FX_FLOAT fScaleY = FXSYS_fabs(ctm.d); 244 FX_RECT rect = bbox.GetOutterRect(); 245 CFX_DIBitmap bitmap, Backdrop; 246 if (!CreateCompatibleBitmap(&bitmap, FXSYS_round(rect.Width() * fScaleX), 247 FXSYS_round(rect.Height() * fScaleY))) { 248 return FALSE; 249 } 250 if (bitmap.HasAlpha()) { 251 bitmap.Clear(0); 252 Backdrop.Copy(&bitmap); 253 } else { 254 if (!m_pDeviceDriver->GetDIBits(&bitmap, rect.left, rect.top, NULL)) { 255 return FALSE; 256 } 257 Backdrop.Copy(&bitmap); 258 } 259 CFX_FxgeDevice bitmap_device; 260 bitmap_device.Attach(&bitmap, 0, FALSE, &Backdrop, TRUE); 261 CFX_Matrix matrix; 262 if (pObject2Device) { 263 matrix = *pObject2Device; 264 } 265 matrix.TranslateI(-rect.left, -rect.top); 266 matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0); 267 if (!bitmap_device.GetDeviceDriver()->DrawPath( 268 pPathData, &matrix, pGraphState, fill_color, stroke_color, 269 fill_mode, alpha_flag, pIccTransform, blend_type)) { 270 return FALSE; 271 } 272 FX_RECT src_rect(0, 0, FXSYS_round(rect.Width() * fScaleX), 273 FXSYS_round(rect.Height() * fScaleY)); 274 return m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, rect.left, 275 rect.top, FXDIB_BLEND_NORMAL); 276 } 277 return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState, 278 fill_color, stroke_color, fill_mode, 279 alpha_flag, pIccTransform, blend_type); 280 } 281 FX_BOOL CFX_RenderDevice::SetPixel(int x, 282 int y, 283 FX_DWORD color, 284 int alpha_flag, 285 void* pIccTransform) { 286 if (m_pDeviceDriver->SetPixel(x, y, color, alpha_flag, pIccTransform)) { 287 return TRUE; 288 } 289 FX_RECT rect(x, y, x + 1, y + 1); 290 return FillRect(&rect, color, alpha_flag, pIccTransform); 291 } 292 FX_BOOL CFX_RenderDevice::FillRect(const FX_RECT* pRect, 293 FX_DWORD fill_color, 294 int alpha_flag, 295 void* pIccTransform, 296 int blend_type) { 297 if (m_pDeviceDriver->FillRect(pRect, fill_color, alpha_flag, pIccTransform, 298 blend_type)) { 299 return TRUE; 300 } 301 if (!(m_RenderCaps & FXRC_GET_BITS)) { 302 return FALSE; 303 } 304 CFX_DIBitmap bitmap; 305 if (!CreateCompatibleBitmap(&bitmap, pRect->Width(), pRect->Height())) { 306 return FALSE; 307 } 308 if (!m_pDeviceDriver->GetDIBits(&bitmap, pRect->left, pRect->top)) { 309 return FALSE; 310 } 311 if (!bitmap.CompositeRect(0, 0, pRect->Width(), pRect->Height(), fill_color, 312 alpha_flag, pIccTransform)) { 313 return FALSE; 314 } 315 FX_RECT src_rect(0, 0, pRect->Width(), pRect->Height()); 316 m_pDeviceDriver->SetDIBits(&bitmap, 0, &src_rect, pRect->left, pRect->top, 317 FXDIB_BLEND_NORMAL); 318 return TRUE; 319 } 320 FX_BOOL CFX_RenderDevice::DrawCosmeticLine(FX_FLOAT x1, 321 FX_FLOAT y1, 322 FX_FLOAT x2, 323 FX_FLOAT y2, 324 FX_DWORD color, 325 int fill_mode, 326 int alpha_flag, 327 void* pIccTransform, 328 int blend_type) { 329 if (((m_RenderCaps & FXRC_ALPHA_PATH) && 330 (FXGETFLAG_COLORTYPE(alpha_flag) && 331 FXGETFLAG_ALPHA_FILL(alpha_flag) == 0xff)) || 332 color >= 0xff000000) 333 if (m_pDeviceDriver->DrawCosmeticLine(x1, y1, x2, y2, color, alpha_flag, 334 pIccTransform, blend_type)) { 335 return TRUE; 336 } 337 CFX_GraphStateData graph_state; 338 CFX_PathData path; 339 path.SetPointCount(2); 340 path.SetPoint(0, x1, y1, FXPT_MOVETO); 341 path.SetPoint(1, x2, y2, FXPT_LINETO); 342 return m_pDeviceDriver->DrawPath(&path, NULL, &graph_state, 0, color, 343 fill_mode, alpha_flag, pIccTransform, 344 blend_type); 345 } 346 FX_BOOL CFX_RenderDevice::GetDIBits(CFX_DIBitmap* pBitmap, 347 int left, 348 int top, 349 void* pIccTransform) { 350 if (!(m_RenderCaps & FXRC_GET_BITS)) { 351 return FALSE; 352 } 353 return m_pDeviceDriver->GetDIBits(pBitmap, left, top, pIccTransform); 354 } 355 CFX_DIBitmap* CFX_RenderDevice::GetBackDrop() { 356 return m_pDeviceDriver->GetBackDrop(); 357 } 358 FX_BOOL CFX_RenderDevice::SetDIBits(const CFX_DIBSource* pBitmap, 359 int left, 360 int top, 361 int blend_mode, 362 void* pIccTransform) { 363 ASSERT(!pBitmap->IsAlphaMask()); 364 CFX_Matrix ctm = GetCTM(); 365 FX_FLOAT fScaleX = FXSYS_fabs(ctm.a); 366 FX_FLOAT fScaleY = FXSYS_fabs(ctm.d); 367 FX_RECT dest_rect(left, top, 368 FXSYS_round(left + pBitmap->GetWidth() / fScaleX), 369 FXSYS_round(top + pBitmap->GetHeight() / fScaleY)); 370 dest_rect.Intersect(m_ClipBox); 371 if (dest_rect.IsEmpty()) { 372 return TRUE; 373 } 374 FX_RECT src_rect(dest_rect.left - left, dest_rect.top - top, 375 dest_rect.left - left + dest_rect.Width(), 376 dest_rect.top - top + dest_rect.Height()); 377 src_rect.left = FXSYS_round(src_rect.left * fScaleX); 378 src_rect.top = FXSYS_round(src_rect.top * fScaleY); 379 src_rect.right = FXSYS_round(src_rect.right * fScaleX); 380 src_rect.bottom = FXSYS_round(src_rect.bottom * fScaleY); 381 if ((blend_mode != FXDIB_BLEND_NORMAL && !(m_RenderCaps & FXRC_BLEND_MODE)) || 382 (pBitmap->HasAlpha() && !(m_RenderCaps & FXRC_ALPHA_IMAGE))) { 383 if (!(m_RenderCaps & FXRC_GET_BITS)) { 384 return FALSE; 385 } 386 int bg_pixel_width = FXSYS_round(dest_rect.Width() * fScaleX); 387 int bg_pixel_height = FXSYS_round(dest_rect.Height() * fScaleY); 388 CFX_DIBitmap background; 389 if (!background.Create( 390 bg_pixel_width, bg_pixel_height, 391 (m_RenderCaps & FXRC_CMYK_OUTPUT) ? FXDIB_Cmyk : FXDIB_Rgb32)) { 392 return FALSE; 393 } 394 if (!m_pDeviceDriver->GetDIBits(&background, dest_rect.left, 395 dest_rect.top)) { 396 return FALSE; 397 } 398 if (!background.CompositeBitmap(0, 0, bg_pixel_width, bg_pixel_height, 399 pBitmap, src_rect.left, src_rect.top, 400 blend_mode, NULL, FALSE, pIccTransform)) { 401 return FALSE; 402 } 403 FX_RECT src_rect(0, 0, bg_pixel_width, bg_pixel_height); 404 return m_pDeviceDriver->SetDIBits(&background, 0, &src_rect, dest_rect.left, 405 dest_rect.top, FXDIB_BLEND_NORMAL); 406 } 407 return m_pDeviceDriver->SetDIBits(pBitmap, 0, &src_rect, dest_rect.left, 408 dest_rect.top, blend_mode, 0, 409 pIccTransform); 410 } 411 FX_BOOL CFX_RenderDevice::StretchDIBits(const CFX_DIBSource* pBitmap, 412 int left, 413 int top, 414 int dest_width, 415 int dest_height, 416 FX_DWORD flags, 417 void* pIccTransform, 418 int blend_mode) { 419 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height); 420 FX_RECT clip_box = m_ClipBox; 421 clip_box.Intersect(dest_rect); 422 if (clip_box.IsEmpty()) { 423 return TRUE; 424 } 425 return m_pDeviceDriver->StretchDIBits(pBitmap, 0, left, top, dest_width, 426 dest_height, &clip_box, flags, 0, 427 pIccTransform, blend_mode); 428 } 429 FX_BOOL CFX_RenderDevice::SetBitMask(const CFX_DIBSource* pBitmap, 430 int left, 431 int top, 432 FX_DWORD argb, 433 int alpha_flag, 434 void* pIccTransform) { 435 FX_RECT src_rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight()); 436 return m_pDeviceDriver->SetDIBits(pBitmap, argb, &src_rect, left, top, 437 FXDIB_BLEND_NORMAL, alpha_flag, 438 pIccTransform); 439 } 440 FX_BOOL CFX_RenderDevice::StretchBitMask(const CFX_DIBSource* pBitmap, 441 int left, 442 int top, 443 int dest_width, 444 int dest_height, 445 FX_DWORD argb, 446 FX_DWORD flags, 447 int alpha_flag, 448 void* pIccTransform) { 449 FX_RECT dest_rect(left, top, left + dest_width, top + dest_height); 450 FX_RECT clip_box = m_ClipBox; 451 clip_box.Intersect(dest_rect); 452 return m_pDeviceDriver->StretchDIBits(pBitmap, argb, left, top, dest_width, 453 dest_height, &clip_box, flags, 454 alpha_flag, pIccTransform); 455 } 456 FX_BOOL CFX_RenderDevice::StartDIBits(const CFX_DIBSource* pBitmap, 457 int bitmap_alpha, 458 FX_DWORD argb, 459 const CFX_Matrix* pMatrix, 460 FX_DWORD flags, 461 void*& handle, 462 int alpha_flag, 463 void* pIccTransform, 464 int blend_mode) { 465 return m_pDeviceDriver->StartDIBits(pBitmap, bitmap_alpha, argb, pMatrix, 466 flags, handle, alpha_flag, pIccTransform, 467 blend_mode); 468 } 469 FX_BOOL CFX_RenderDevice::ContinueDIBits(void* handle, IFX_Pause* pPause) { 470 return m_pDeviceDriver->ContinueDIBits(handle, pPause); 471 } 472 void CFX_RenderDevice::CancelDIBits(void* handle) { 473 m_pDeviceDriver->CancelDIBits(handle); 474 } 475