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