OLD | NEW |
| (Empty) |
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/fpdfapi/fpdf_render/render_int.h" | |
8 | |
9 #include <memory> | |
10 | |
11 #include "core/fpdfapi/cpdf_modulemgr.h" | |
12 #include "core/fpdfapi/font/cpdf_type3char.h" | |
13 #include "core/fpdfapi/font/cpdf_type3font.h" | |
14 #include "core/fpdfapi/fpdf_render/cpdf_pagerendercache.h" | |
15 #include "core/fpdfapi/fpdf_render/cpdf_progressiverenderer.h" | |
16 #include "core/fpdfapi/fpdf_render/cpdf_renderoptions.h" | |
17 #include "core/fpdfapi/fpdf_render/cpdf_textrenderer.h" | |
18 #include "core/fpdfapi/fpdf_render/cpdf_type3cache.h" | |
19 #include "core/fpdfapi/page/cpdf_form.h" | |
20 #include "core/fpdfapi/page/cpdf_formobject.h" | |
21 #include "core/fpdfapi/page/cpdf_graphicstates.h" | |
22 #include "core/fpdfapi/page/cpdf_image.h" | |
23 #include "core/fpdfapi/page/cpdf_imageobject.h" | |
24 #include "core/fpdfapi/page/cpdf_page.h" | |
25 #include "core/fpdfapi/page/cpdf_pageobject.h" | |
26 #include "core/fpdfapi/page/cpdf_pathobject.h" | |
27 #include "core/fpdfapi/page/cpdf_textobject.h" | |
28 #include "core/fpdfapi/page/pageint.h" | |
29 #include "core/fpdfapi/parser/cpdf_array.h" | |
30 #include "core/fpdfapi/parser/cpdf_dictionary.h" | |
31 #include "core/fpdfapi/parser/cpdf_document.h" | |
32 #include "core/fpdfdoc/cpdf_occontext.h" | |
33 #include "core/fxge/cfx_fxgedevice.h" | |
34 #include "core/fxge/cfx_graphstatedata.h" | |
35 #include "core/fxge/cfx_pathdata.h" | |
36 #include "core/fxge/cfx_renderdevice.h" | |
37 | |
38 CPDF_DocRenderData::CPDF_DocRenderData(CPDF_Document* pPDFDoc) | |
39 : m_pPDFDoc(pPDFDoc) {} | |
40 | |
41 CPDF_DocRenderData::~CPDF_DocRenderData() { | |
42 Clear(TRUE); | |
43 } | |
44 | |
45 void CPDF_DocRenderData::Clear(FX_BOOL bRelease) { | |
46 for (auto it = m_Type3FaceMap.begin(); it != m_Type3FaceMap.end();) { | |
47 auto curr_it = it++; | |
48 CPDF_CountedObject<CPDF_Type3Cache>* cache = curr_it->second; | |
49 if (bRelease || cache->use_count() < 2) { | |
50 delete cache->get(); | |
51 delete cache; | |
52 m_Type3FaceMap.erase(curr_it); | |
53 } | |
54 } | |
55 | |
56 for (auto it = m_TransferFuncMap.begin(); it != m_TransferFuncMap.end();) { | |
57 auto curr_it = it++; | |
58 CPDF_CountedObject<CPDF_TransferFunc>* value = curr_it->second; | |
59 if (bRelease || value->use_count() < 2) { | |
60 delete value->get(); | |
61 delete value; | |
62 m_TransferFuncMap.erase(curr_it); | |
63 } | |
64 } | |
65 } | |
66 | |
67 CPDF_Type3Cache* CPDF_DocRenderData::GetCachedType3(CPDF_Type3Font* pFont) { | |
68 CPDF_CountedObject<CPDF_Type3Cache>* pCache; | |
69 auto it = m_Type3FaceMap.find(pFont); | |
70 if (it == m_Type3FaceMap.end()) { | |
71 CPDF_Type3Cache* pType3 = new CPDF_Type3Cache(pFont); | |
72 pCache = new CPDF_CountedObject<CPDF_Type3Cache>(pType3); | |
73 m_Type3FaceMap[pFont] = pCache; | |
74 } else { | |
75 pCache = it->second; | |
76 } | |
77 return pCache->AddRef(); | |
78 } | |
79 | |
80 void CPDF_DocRenderData::ReleaseCachedType3(CPDF_Type3Font* pFont) { | |
81 auto it = m_Type3FaceMap.find(pFont); | |
82 if (it != m_Type3FaceMap.end()) | |
83 it->second->RemoveRef(); | |
84 } | |
85 | |
86 CPDF_RenderOptions::CPDF_RenderOptions() | |
87 : m_ColorMode(RENDER_COLOR_NORMAL), | |
88 m_Flags(RENDER_CLEARTYPE), | |
89 m_Interpolation(0), | |
90 m_AddFlags(0), | |
91 m_pOCContext(nullptr), | |
92 m_dwLimitCacheSize(1024 * 1024 * 100), | |
93 m_HalftoneLimit(-1), | |
94 m_bDrawAnnots(false) {} | |
95 | |
96 CPDF_RenderOptions::CPDF_RenderOptions(const CPDF_RenderOptions& rhs) | |
97 : m_ColorMode(rhs.m_ColorMode), | |
98 m_BackColor(rhs.m_BackColor), | |
99 m_ForeColor(rhs.m_ForeColor), | |
100 m_Flags(rhs.m_Flags), | |
101 m_Interpolation(rhs.m_Interpolation), | |
102 m_AddFlags(rhs.m_AddFlags), | |
103 m_pOCContext(rhs.m_pOCContext), | |
104 m_dwLimitCacheSize(rhs.m_dwLimitCacheSize), | |
105 m_HalftoneLimit(rhs.m_HalftoneLimit), | |
106 m_bDrawAnnots(rhs.m_bDrawAnnots) {} | |
107 | |
108 FX_ARGB CPDF_RenderOptions::TranslateColor(FX_ARGB argb) const { | |
109 if (m_ColorMode == RENDER_COLOR_NORMAL) { | |
110 return argb; | |
111 } | |
112 if (m_ColorMode == RENDER_COLOR_ALPHA) { | |
113 return argb; | |
114 } | |
115 int a, r, g, b; | |
116 ArgbDecode(argb, a, r, g, b); | |
117 int gray = FXRGB2GRAY(r, g, b); | |
118 if (m_ColorMode == RENDER_COLOR_TWOCOLOR) { | |
119 int color = (r - gray) * (r - gray) + (g - gray) * (g - gray) + | |
120 (b - gray) * (b - gray); | |
121 if (gray < 35 && color < 20) { | |
122 return ArgbEncode(a, m_ForeColor); | |
123 } | |
124 if (gray > 221 && color < 20) { | |
125 return ArgbEncode(a, m_BackColor); | |
126 } | |
127 return argb; | |
128 } | |
129 int fr = FXSYS_GetRValue(m_ForeColor); | |
130 int fg = FXSYS_GetGValue(m_ForeColor); | |
131 int fb = FXSYS_GetBValue(m_ForeColor); | |
132 int br = FXSYS_GetRValue(m_BackColor); | |
133 int bg = FXSYS_GetGValue(m_BackColor); | |
134 int bb = FXSYS_GetBValue(m_BackColor); | |
135 r = (br - fr) * gray / 255 + fr; | |
136 g = (bg - fg) * gray / 255 + fg; | |
137 b = (bb - fb) * gray / 255 + fb; | |
138 return ArgbEncode(a, r, g, b); | |
139 } | |
140 | |
141 // static | |
142 int CPDF_RenderStatus::s_CurrentRecursionDepth = 0; | |
143 | |
144 CPDF_RenderStatus::CPDF_RenderStatus() | |
145 : m_pFormResource(nullptr), | |
146 m_pPageResource(nullptr), | |
147 m_pContext(nullptr), | |
148 m_bStopped(FALSE), | |
149 m_pDevice(nullptr), | |
150 m_pCurObj(nullptr), | |
151 m_pStopObj(nullptr), | |
152 m_HalftoneLimit(0), | |
153 m_bPrint(FALSE), | |
154 m_Transparency(0), | |
155 m_bDropObjects(FALSE), | |
156 m_bStdCS(FALSE), | |
157 m_GroupFamily(0), | |
158 m_bLoadMask(FALSE), | |
159 m_pType3Char(nullptr), | |
160 m_T3FillColor(0), | |
161 m_curBlend(FXDIB_BLEND_NORMAL) {} | |
162 | |
163 CPDF_RenderStatus::~CPDF_RenderStatus() {} | |
164 | |
165 FX_BOOL CPDF_RenderStatus::Initialize(CPDF_RenderContext* pContext, | |
166 CFX_RenderDevice* pDevice, | |
167 const CFX_Matrix* pDeviceMatrix, | |
168 const CPDF_PageObject* pStopObj, | |
169 const CPDF_RenderStatus* pParentState, | |
170 const CPDF_GraphicStates* pInitialStates, | |
171 const CPDF_RenderOptions* pOptions, | |
172 int transparency, | |
173 FX_BOOL bDropObjects, | |
174 CPDF_Dictionary* pFormResource, | |
175 FX_BOOL bStdCS, | |
176 CPDF_Type3Char* pType3Char, | |
177 FX_ARGB fill_color, | |
178 uint32_t GroupFamily, | |
179 FX_BOOL bLoadMask) { | |
180 m_pContext = pContext; | |
181 m_pDevice = pDevice; | |
182 m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY; | |
183 if (pDeviceMatrix) { | |
184 m_DeviceMatrix = *pDeviceMatrix; | |
185 } | |
186 m_pStopObj = pStopObj; | |
187 if (pOptions) { | |
188 m_Options = *pOptions; | |
189 } | |
190 m_bDropObjects = bDropObjects; | |
191 m_bStdCS = bStdCS; | |
192 m_T3FillColor = fill_color; | |
193 m_pType3Char = pType3Char; | |
194 m_GroupFamily = GroupFamily; | |
195 m_bLoadMask = bLoadMask; | |
196 m_pFormResource = pFormResource; | |
197 m_pPageResource = m_pContext->GetPageResources(); | |
198 if (pInitialStates && !m_pType3Char) { | |
199 m_InitialStates.CopyStates(*pInitialStates); | |
200 if (pParentState) { | |
201 if (!m_InitialStates.m_ColorState.HasFillColor()) { | |
202 m_InitialStates.m_ColorState.SetFillRGB( | |
203 pParentState->m_InitialStates.m_ColorState.GetFillRGB()); | |
204 m_InitialStates.m_ColorState.GetMutableFillColor()->Copy( | |
205 pParentState->m_InitialStates.m_ColorState.GetFillColor()); | |
206 } | |
207 if (!m_InitialStates.m_ColorState.HasStrokeColor()) { | |
208 m_InitialStates.m_ColorState.SetStrokeRGB( | |
209 pParentState->m_InitialStates.m_ColorState.GetFillRGB()); | |
210 m_InitialStates.m_ColorState.GetMutableStrokeColor()->Copy( | |
211 pParentState->m_InitialStates.m_ColorState.GetStrokeColor()); | |
212 } | |
213 } | |
214 } else { | |
215 m_InitialStates.DefaultStates(); | |
216 } | |
217 m_pImageRenderer.reset(); | |
218 m_Transparency = transparency; | |
219 return TRUE; | |
220 } | |
221 void CPDF_RenderStatus::RenderObjectList( | |
222 const CPDF_PageObjectHolder* pObjectHolder, | |
223 const CFX_Matrix* pObj2Device) { | |
224 #if defined _SKIA_SUPPORT_ | |
225 DebugVerifyDeviceIsPreMultiplied(); | |
226 #endif | |
227 CFX_FloatRect clip_rect(m_pDevice->GetClipBox()); | |
228 CFX_Matrix device2object; | |
229 device2object.SetReverse(*pObj2Device); | |
230 device2object.TransformRect(clip_rect); | |
231 | |
232 for (const auto& pCurObj : *pObjectHolder->GetPageObjectList()) { | |
233 if (pCurObj.get() == m_pStopObj) { | |
234 m_bStopped = TRUE; | |
235 return; | |
236 } | |
237 if (!pCurObj) | |
238 continue; | |
239 | |
240 if (pCurObj->m_Left > clip_rect.right || | |
241 pCurObj->m_Right < clip_rect.left || | |
242 pCurObj->m_Bottom > clip_rect.top || | |
243 pCurObj->m_Top < clip_rect.bottom) { | |
244 continue; | |
245 } | |
246 RenderSingleObject(pCurObj.get(), pObj2Device); | |
247 if (m_bStopped) | |
248 return; | |
249 } | |
250 #if defined _SKIA_SUPPORT_ | |
251 DebugVerifyDeviceIsPreMultiplied(); | |
252 #endif | |
253 } | |
254 | |
255 void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj, | |
256 const CFX_Matrix* pObj2Device) { | |
257 #if defined _SKIA_SUPPORT_ | |
258 DebugVerifyDeviceIsPreMultiplied(); | |
259 #endif | |
260 CFX_AutoRestorer<int> restorer(&s_CurrentRecursionDepth); | |
261 if (++s_CurrentRecursionDepth > kRenderMaxRecursionDepth) { | |
262 return; | |
263 } | |
264 m_pCurObj = pObj; | |
265 if (m_Options.m_pOCContext && pObj->m_ContentMark) { | |
266 if (!m_Options.m_pOCContext->CheckObjectVisible(pObj)) { | |
267 return; | |
268 } | |
269 } | |
270 ProcessClipPath(pObj->m_ClipPath, pObj2Device); | |
271 if (ProcessTransparency(pObj, pObj2Device)) { | |
272 return; | |
273 } | |
274 ProcessObjectNoClip(pObj, pObj2Device); | |
275 #if defined _SKIA_SUPPORT_ | |
276 DebugVerifyDeviceIsPreMultiplied(); | |
277 #endif | |
278 } | |
279 | |
280 FX_BOOL CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj, | |
281 const CFX_Matrix* pObj2Device, | |
282 IFX_Pause* pPause) { | |
283 if (m_pImageRenderer) { | |
284 if (m_pImageRenderer->Continue(pPause)) | |
285 return TRUE; | |
286 | |
287 if (!m_pImageRenderer->m_Result) | |
288 DrawObjWithBackground(pObj, pObj2Device); | |
289 m_pImageRenderer.reset(); | |
290 return FALSE; | |
291 } | |
292 | |
293 m_pCurObj = pObj; | |
294 if (m_Options.m_pOCContext && pObj->m_ContentMark && | |
295 !m_Options.m_pOCContext->CheckObjectVisible(pObj)) { | |
296 return FALSE; | |
297 } | |
298 | |
299 ProcessClipPath(pObj->m_ClipPath, pObj2Device); | |
300 if (ProcessTransparency(pObj, pObj2Device)) | |
301 return FALSE; | |
302 | |
303 if (pObj->IsImage()) { | |
304 m_pImageRenderer.reset(new CPDF_ImageRenderer); | |
305 if (!m_pImageRenderer->Start(this, pObj, pObj2Device, FALSE)) { | |
306 if (!m_pImageRenderer->m_Result) | |
307 DrawObjWithBackground(pObj, pObj2Device); | |
308 m_pImageRenderer.reset(); | |
309 return FALSE; | |
310 } | |
311 return ContinueSingleObject(pObj, pObj2Device, pPause); | |
312 } | |
313 | |
314 ProcessObjectNoClip(pObj, pObj2Device); | |
315 return FALSE; | |
316 } | |
317 | |
318 FX_BOOL CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj, | |
319 const CFX_Matrix* pObj2Device, | |
320 FX_BOOL bLogical, | |
321 FX_RECT& rect) const { | |
322 rect = pObj->GetBBox(pObj2Device); | |
323 FX_RECT rtClip = m_pDevice->GetClipBox(); | |
324 if (!bLogical) { | |
325 CFX_Matrix dCTM = m_pDevice->GetCTM(); | |
326 FX_FLOAT a = FXSYS_fabs(dCTM.a); | |
327 FX_FLOAT d = FXSYS_fabs(dCTM.d); | |
328 if (a != 1.0f || d != 1.0f) { | |
329 rect.right = rect.left + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Width() * a); | |
330 rect.bottom = rect.top + (int32_t)FXSYS_ceil((FX_FLOAT)rect.Height() * d); | |
331 rtClip.right = | |
332 rtClip.left + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Width() * a); | |
333 rtClip.bottom = | |
334 rtClip.top + (int32_t)FXSYS_ceil((FX_FLOAT)rtClip.Height() * d); | |
335 } | |
336 } | |
337 rect.Intersect(rtClip); | |
338 return rect.IsEmpty(); | |
339 } | |
340 | |
341 void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj, | |
342 const CFX_Matrix* pObj2Device) { | |
343 #if defined _SKIA_SUPPORT_ | |
344 DebugVerifyDeviceIsPreMultiplied(); | |
345 #endif | |
346 FX_BOOL bRet = FALSE; | |
347 switch (pObj->GetType()) { | |
348 case CPDF_PageObject::TEXT: | |
349 bRet = ProcessText(pObj->AsText(), pObj2Device, nullptr); | |
350 break; | |
351 case CPDF_PageObject::PATH: | |
352 bRet = ProcessPath(pObj->AsPath(), pObj2Device); | |
353 break; | |
354 case CPDF_PageObject::IMAGE: | |
355 bRet = ProcessImage(pObj->AsImage(), pObj2Device); | |
356 break; | |
357 case CPDF_PageObject::SHADING: | |
358 ProcessShading(pObj->AsShading(), pObj2Device); | |
359 return; | |
360 case CPDF_PageObject::FORM: | |
361 bRet = ProcessForm(pObj->AsForm(), pObj2Device); | |
362 break; | |
363 } | |
364 if (!bRet) | |
365 DrawObjWithBackground(pObj, pObj2Device); | |
366 #if defined _SKIA_SUPPORT_ | |
367 DebugVerifyDeviceIsPreMultiplied(); | |
368 #endif | |
369 } | |
370 | |
371 FX_BOOL CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj, | |
372 const CFX_Matrix* pObj2Device) { | |
373 FX_BOOL bRet = FALSE; | |
374 switch (pObj->GetType()) { | |
375 case CPDF_PageObject::PATH: | |
376 bRet = ProcessPath(pObj->AsPath(), pObj2Device); | |
377 break; | |
378 case CPDF_PageObject::IMAGE: | |
379 bRet = ProcessImage(pObj->AsImage(), pObj2Device); | |
380 break; | |
381 case CPDF_PageObject::FORM: | |
382 bRet = ProcessForm(pObj->AsForm(), pObj2Device); | |
383 break; | |
384 default: | |
385 break; | |
386 } | |
387 return bRet; | |
388 } | |
389 void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix& matrix) const { | |
390 CFX_Matrix dCTM = m_pDevice->GetCTM(); | |
391 matrix.a *= FXSYS_fabs(dCTM.a); | |
392 matrix.d *= FXSYS_fabs(dCTM.d); | |
393 } | |
394 | |
395 void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj, | |
396 const CFX_Matrix* pObj2Device) { | |
397 FX_RECT rect; | |
398 if (GetObjectClippedRect(pObj, pObj2Device, FALSE, rect)) { | |
399 return; | |
400 } | |
401 int res = 300; | |
402 if (pObj->IsImage() && | |
403 m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { | |
404 res = 0; | |
405 } | |
406 CPDF_ScaledRenderBuffer buffer; | |
407 if (!buffer.Initialize(m_pContext, m_pDevice, rect, pObj, &m_Options, res)) { | |
408 return; | |
409 } | |
410 CFX_Matrix matrix = *pObj2Device; | |
411 matrix.Concat(*buffer.GetMatrix()); | |
412 GetScaledMatrix(matrix); | |
413 CPDF_Dictionary* pFormResource = nullptr; | |
414 if (pObj->IsForm()) { | |
415 const CPDF_FormObject* pFormObj = pObj->AsForm(); | |
416 if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) { | |
417 pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources"); | |
418 } | |
419 } | |
420 CPDF_RenderStatus status; | |
421 status.Initialize(m_pContext, buffer.GetDevice(), buffer.GetMatrix(), nullptr, | |
422 nullptr, nullptr, &m_Options, m_Transparency, | |
423 m_bDropObjects, pFormResource); | |
424 status.RenderSingleObject(pObj, &matrix); | |
425 buffer.OutputToDevice(); | |
426 } | |
427 | |
428 FX_BOOL CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj, | |
429 const CFX_Matrix* pObj2Device) { | |
430 #if defined _SKIA_SUPPORT_ | |
431 DebugVerifyDeviceIsPreMultiplied(); | |
432 #endif | |
433 CPDF_Dictionary* pOC = pFormObj->m_pForm->m_pFormDict->GetDictFor("OC"); | |
434 if (pOC && m_Options.m_pOCContext && | |
435 !m_Options.m_pOCContext->CheckOCGVisible(pOC)) { | |
436 return TRUE; | |
437 } | |
438 CFX_Matrix matrix = pFormObj->m_FormMatrix; | |
439 matrix.Concat(*pObj2Device); | |
440 CPDF_Dictionary* pResources = nullptr; | |
441 if (pFormObj->m_pForm && pFormObj->m_pForm->m_pFormDict) { | |
442 pResources = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources"); | |
443 } | |
444 CPDF_RenderStatus status; | |
445 status.Initialize(m_pContext, m_pDevice, nullptr, m_pStopObj, this, pFormObj, | |
446 &m_Options, m_Transparency, m_bDropObjects, pResources, | |
447 FALSE); | |
448 status.m_curBlend = m_curBlend; | |
449 m_pDevice->SaveState(); | |
450 status.RenderObjectList(pFormObj->m_pForm.get(), &matrix); | |
451 m_bStopped = status.m_bStopped; | |
452 m_pDevice->RestoreState(false); | |
453 #if defined _SKIA_SUPPORT_ | |
454 DebugVerifyDeviceIsPreMultiplied(); | |
455 #endif | |
456 return TRUE; | |
457 } | |
458 | |
459 FX_BOOL IsAvailableMatrix(const CFX_Matrix& matrix) { | |
460 if (matrix.a == 0 || matrix.d == 0) { | |
461 return matrix.b != 0 && matrix.c != 0; | |
462 } | |
463 if (matrix.b == 0 || matrix.c == 0) { | |
464 return matrix.a != 0 && matrix.d != 0; | |
465 } | |
466 return TRUE; | |
467 } | |
468 | |
469 FX_BOOL CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj, | |
470 const CFX_Matrix* pObj2Device) { | |
471 int FillType = pPathObj->m_FillType; | |
472 FX_BOOL bStroke = pPathObj->m_bStroke; | |
473 ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke); | |
474 if (FillType == 0 && !bStroke) | |
475 return TRUE; | |
476 | |
477 uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0; | |
478 uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0; | |
479 CFX_Matrix path_matrix = pPathObj->m_Matrix; | |
480 path_matrix.Concat(*pObj2Device); | |
481 if (!IsAvailableMatrix(path_matrix)) | |
482 return TRUE; | |
483 | |
484 if (FillType && (m_Options.m_Flags & RENDER_RECT_AA)) | |
485 FillType |= FXFILL_RECT_AA; | |
486 if (m_Options.m_Flags & RENDER_FILL_FULLCOVER) | |
487 FillType |= FXFILL_FULLCOVER; | |
488 if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) | |
489 FillType |= FXFILL_NOPATHSMOOTH; | |
490 if (bStroke) | |
491 FillType |= FX_FILL_STROKE; | |
492 | |
493 const CPDF_PageObject* pPageObj = | |
494 static_cast<const CPDF_PageObject*>(pPathObj); | |
495 if (pPageObj->m_GeneralState.GetStrokeAdjust()) | |
496 FillType |= FX_STROKE_ADJUST; | |
497 if (m_pType3Char) | |
498 FillType |= FX_FILL_TEXT_MODE; | |
499 | |
500 CFX_GraphState graphState = pPathObj->m_GraphState; | |
501 if (m_Options.m_Flags & RENDER_THINLINE) | |
502 graphState.SetLineWidth(0); | |
503 return m_pDevice->DrawPathWithBlend( | |
504 pPathObj->m_Path.GetObject(), &path_matrix, graphState.GetObject(), | |
505 fill_argb, stroke_argb, FillType, m_curBlend); | |
506 } | |
507 | |
508 CPDF_TransferFunc* CPDF_RenderStatus::GetTransferFunc(CPDF_Object* pObj) const { | |
509 ASSERT(pObj); | |
510 CPDF_DocRenderData* pDocCache = m_pContext->GetDocument()->GetRenderData(); | |
511 return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr; | |
512 } | |
513 | |
514 FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj, | |
515 FX_BOOL bType3) const { | |
516 const CPDF_ColorState* pColorState = &pObj->m_ColorState; | |
517 if (m_pType3Char && !bType3 && | |
518 (!m_pType3Char->m_bColored || | |
519 (m_pType3Char->m_bColored && | |
520 (!*pColorState || pColorState->GetFillColor()->IsNull())))) { | |
521 return m_T3FillColor; | |
522 } | |
523 if (!*pColorState || pColorState->GetFillColor()->IsNull()) | |
524 pColorState = &m_InitialStates.m_ColorState; | |
525 | |
526 FX_COLORREF rgb = pColorState->GetFillRGB(); | |
527 if (rgb == (uint32_t)-1) | |
528 return 0; | |
529 | |
530 int32_t alpha = | |
531 static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255)); | |
532 if (pObj->m_GeneralState.GetTR()) { | |
533 if (!pObj->m_GeneralState.GetTransferFunc()) { | |
534 pObj->m_GeneralState.SetTransferFunc( | |
535 GetTransferFunc(pObj->m_GeneralState.GetTR())); | |
536 } | |
537 if (pObj->m_GeneralState.GetTransferFunc()) | |
538 rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb); | |
539 } | |
540 return m_Options.TranslateColor(ArgbEncode(alpha, rgb)); | |
541 } | |
542 | |
543 FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const { | |
544 const CPDF_ColorState* pColorState = &pObj->m_ColorState; | |
545 if (m_pType3Char && | |
546 (!m_pType3Char->m_bColored || | |
547 (m_pType3Char->m_bColored && | |
548 (!*pColorState || pColorState->GetStrokeColor()->IsNull())))) { | |
549 return m_T3FillColor; | |
550 } | |
551 if (!*pColorState || pColorState->GetStrokeColor()->IsNull()) | |
552 pColorState = &m_InitialStates.m_ColorState; | |
553 | |
554 FX_COLORREF rgb = pColorState->GetStrokeRGB(); | |
555 if (rgb == (uint32_t)-1) | |
556 return 0; | |
557 | |
558 int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() * | |
559 255); // not rounded. | |
560 if (pObj->m_GeneralState.GetTR()) { | |
561 if (!pObj->m_GeneralState.GetTransferFunc()) { | |
562 pObj->m_GeneralState.SetTransferFunc( | |
563 GetTransferFunc(pObj->m_GeneralState.GetTR())); | |
564 } | |
565 if (pObj->m_GeneralState.GetTransferFunc()) | |
566 rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb); | |
567 } | |
568 return m_Options.TranslateColor(ArgbEncode(alpha, rgb)); | |
569 } | |
570 void CPDF_RenderStatus::ProcessClipPath(CPDF_ClipPath ClipPath, | |
571 const CFX_Matrix* pObj2Device) { | |
572 if (!ClipPath) { | |
573 if (m_LastClipPath) { | |
574 m_pDevice->RestoreState(true); | |
575 m_LastClipPath.SetNull(); | |
576 } | |
577 return; | |
578 } | |
579 if (m_LastClipPath == ClipPath) | |
580 return; | |
581 | |
582 m_LastClipPath = ClipPath; | |
583 m_pDevice->RestoreState(true); | |
584 int nClipPath = ClipPath.GetPathCount(); | |
585 for (int i = 0; i < nClipPath; ++i) { | |
586 const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject(); | |
587 if (!pPathData) | |
588 continue; | |
589 | |
590 if (pPathData->GetPointCount() == 0) { | |
591 CFX_PathData EmptyPath; | |
592 EmptyPath.AppendRect(-1, -1, 0, 0); | |
593 int fill_mode = FXFILL_WINDING; | |
594 m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, fill_mode); | |
595 } else { | |
596 int ClipType = ClipPath.GetClipType(i); | |
597 m_pDevice->SetClip_PathFill(pPathData, pObj2Device, ClipType); | |
598 } | |
599 } | |
600 int textcount = ClipPath.GetTextCount(); | |
601 if (textcount == 0) | |
602 return; | |
603 | |
604 if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY && | |
605 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) { | |
606 return; | |
607 } | |
608 | |
609 std::unique_ptr<CFX_PathData> pTextClippingPath; | |
610 for (int i = 0; i < textcount; ++i) { | |
611 CPDF_TextObject* pText = ClipPath.GetText(i); | |
612 if (pText) { | |
613 if (!pTextClippingPath) | |
614 pTextClippingPath.reset(new CFX_PathData); | |
615 ProcessText(pText, pObj2Device, pTextClippingPath.get()); | |
616 continue; | |
617 } | |
618 | |
619 if (!pTextClippingPath) | |
620 continue; | |
621 | |
622 int fill_mode = FXFILL_WINDING; | |
623 if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) | |
624 fill_mode |= FXFILL_NOPATHSMOOTH; | |
625 m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode); | |
626 pTextClippingPath.reset(); | |
627 } | |
628 } | |
629 | |
630 void CPDF_RenderStatus::DrawClipPath(CPDF_ClipPath ClipPath, | |
631 const CFX_Matrix* pObj2Device) { | |
632 if (!ClipPath) | |
633 return; | |
634 | |
635 int fill_mode = 0; | |
636 if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) { | |
637 fill_mode |= FXFILL_NOPATHSMOOTH; | |
638 } | |
639 int nClipPath = ClipPath.GetPathCount(); | |
640 int i; | |
641 for (i = 0; i < nClipPath; i++) { | |
642 const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject(); | |
643 if (!pPathData) { | |
644 continue; | |
645 } | |
646 CFX_GraphStateData stroke_state; | |
647 if (m_Options.m_Flags & RENDER_THINLINE) { | |
648 stroke_state.m_LineWidth = 0; | |
649 } | |
650 m_pDevice->DrawPath(pPathData, pObj2Device, &stroke_state, 0, 0xffff0000, | |
651 fill_mode); | |
652 } | |
653 } | |
654 FX_BOOL CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj, | |
655 const CFX_Matrix* pObj2Device, | |
656 FX_BOOL bStroke) { | |
657 CFX_Matrix path_matrix = pPathObj->m_Matrix; | |
658 path_matrix.Concat(*pObj2Device); | |
659 if (bStroke) { | |
660 CFX_GraphState graphState = pPathObj->m_GraphState; | |
661 if (m_Options.m_Flags & RENDER_THINLINE) | |
662 graphState.SetLineWidth(0); | |
663 return m_pDevice->SetClip_PathStroke(pPathObj->m_Path.GetObject(), | |
664 &path_matrix, graphState.GetObject()); | |
665 } | |
666 int fill_mode = pPathObj->m_FillType; | |
667 if (m_Options.m_Flags & RENDER_NOPATHSMOOTH) { | |
668 fill_mode |= FXFILL_NOPATHSMOOTH; | |
669 } | |
670 return m_pDevice->SetClip_PathFill(pPathObj->m_Path.GetObject(), &path_matrix, | |
671 fill_mode); | |
672 } | |
673 FX_BOOL CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj, | |
674 const CFX_Matrix* pObj2Device) { | |
675 #if defined _SKIA_SUPPORT_ | |
676 DebugVerifyDeviceIsPreMultiplied(); | |
677 #endif | |
678 int blend_type = pPageObj->m_GeneralState.GetBlendType(); | |
679 if (blend_type == FXDIB_BLEND_UNSUPPORTED) | |
680 return TRUE; | |
681 | |
682 CPDF_Dictionary* pSMaskDict = | |
683 ToDictionary(pPageObj->m_GeneralState.GetSoftMask()); | |
684 if (pSMaskDict) { | |
685 if (pPageObj->IsImage() && | |
686 pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) { | |
687 pSMaskDict = nullptr; | |
688 } | |
689 } | |
690 CPDF_Dictionary* pFormResource = nullptr; | |
691 FX_FLOAT group_alpha = 1.0f; | |
692 int Transparency = m_Transparency; | |
693 FX_BOOL bGroupTransparent = FALSE; | |
694 if (pPageObj->IsForm()) { | |
695 const CPDF_FormObject* pFormObj = pPageObj->AsForm(); | |
696 group_alpha = pFormObj->m_GeneralState.GetFillAlpha(); | |
697 Transparency = pFormObj->m_pForm->m_Transparency; | |
698 bGroupTransparent = !!(Transparency & PDFTRANS_ISOLATED); | |
699 if (pFormObj->m_pForm->m_pFormDict) { | |
700 pFormResource = pFormObj->m_pForm->m_pFormDict->GetDictFor("Resources"); | |
701 } | |
702 } | |
703 bool bTextClip = | |
704 (pPageObj->m_ClipPath && pPageObj->m_ClipPath.GetTextCount() && | |
705 m_pDevice->GetDeviceClass() == FXDC_DISPLAY && | |
706 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)); | |
707 if ((m_Options.m_Flags & RENDER_OVERPRINT) && pPageObj->IsImage() && | |
708 pPageObj->m_GeneralState.GetFillOP() && | |
709 pPageObj->m_GeneralState.GetStrokeOP()) { | |
710 CPDF_Document* pDocument = nullptr; | |
711 CPDF_Page* pPage = nullptr; | |
712 if (m_pContext->GetPageCache()) { | |
713 pPage = m_pContext->GetPageCache()->GetPage(); | |
714 pDocument = pPage->m_pDocument; | |
715 } else { | |
716 pDocument = pPageObj->AsImage()->GetImage()->GetDocument(); | |
717 } | |
718 CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : nullptr; | |
719 CPDF_Object* pCSObj = pPageObj->AsImage() | |
720 ->GetImage() | |
721 ->GetStream() | |
722 ->GetDict() | |
723 ->GetDirectObjectFor("ColorSpace"); | |
724 CPDF_ColorSpace* pColorSpace = | |
725 pDocument->LoadColorSpace(pCSObj, pPageResources); | |
726 if (pColorSpace) { | |
727 int format = pColorSpace->GetFamily(); | |
728 if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || | |
729 format == PDFCS_DEVICEN) { | |
730 blend_type = FXDIB_BLEND_DARKEN; | |
731 } | |
732 pDocument->GetPageData()->ReleaseColorSpace(pCSObj); | |
733 } | |
734 } | |
735 if (!pSMaskDict && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL && | |
736 !bTextClip && !bGroupTransparent) { | |
737 return FALSE; | |
738 } | |
739 bool isolated = !!(Transparency & PDFTRANS_ISOLATED); | |
740 if (m_bPrint) { | |
741 FX_BOOL bRet = FALSE; | |
742 int rendCaps = m_pDevice->GetRenderCaps(); | |
743 if (!((Transparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) && | |
744 (rendCaps & FXRC_BLEND_MODE)) { | |
745 int oldBlend = m_curBlend; | |
746 m_curBlend = blend_type; | |
747 bRet = DrawObjWithBlend(pPageObj, pObj2Device); | |
748 m_curBlend = oldBlend; | |
749 } | |
750 if (!bRet) { | |
751 DrawObjWithBackground(pPageObj, pObj2Device); | |
752 } | |
753 return TRUE; | |
754 } | |
755 FX_RECT rect = pPageObj->GetBBox(pObj2Device); | |
756 rect.Intersect(m_pDevice->GetClipBox()); | |
757 if (rect.IsEmpty()) { | |
758 return TRUE; | |
759 } | |
760 CFX_Matrix deviceCTM = m_pDevice->GetCTM(); | |
761 FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a); | |
762 FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d); | |
763 int width = FXSYS_round((FX_FLOAT)rect.Width() * scaleX); | |
764 int height = FXSYS_round((FX_FLOAT)rect.Height() * scaleY); | |
765 CFX_FxgeDevice bitmap_device; | |
766 std::unique_ptr<CFX_DIBitmap> oriDevice; | |
767 if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) { | |
768 oriDevice.reset(new CFX_DIBitmap); | |
769 if (!m_pDevice->CreateCompatibleBitmap(oriDevice.get(), width, height)) | |
770 return TRUE; | |
771 m_pDevice->GetDIBits(oriDevice.get(), rect.left, rect.top); | |
772 } | |
773 if (!bitmap_device.Create(width, height, FXDIB_Argb, oriDevice.get())) | |
774 return TRUE; | |
775 CFX_DIBitmap* bitmap = bitmap_device.GetBitmap(); | |
776 bitmap->Clear(0); | |
777 CFX_Matrix new_matrix = *pObj2Device; | |
778 new_matrix.TranslateI(-rect.left, -rect.top); | |
779 new_matrix.Scale(scaleX, scaleY); | |
780 std::unique_ptr<CFX_DIBitmap> pTextMask; | |
781 if (bTextClip) { | |
782 pTextMask.reset(new CFX_DIBitmap); | |
783 if (!pTextMask->Create(width, height, FXDIB_8bppMask)) | |
784 return TRUE; | |
785 | |
786 pTextMask->Clear(0); | |
787 CFX_FxgeDevice text_device; | |
788 text_device.Attach(pTextMask.get(), false, nullptr, false); | |
789 for (uint32_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); i++) { | |
790 CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i); | |
791 if (!textobj) { | |
792 break; | |
793 } | |
794 CFX_Matrix text_matrix; | |
795 textobj->GetTextMatrix(&text_matrix); | |
796 CPDF_TextRenderer::DrawTextPath( | |
797 &text_device, textobj->m_nChars, textobj->m_pCharCodes, | |
798 textobj->m_pCharPos, textobj->m_TextState.GetFont(), | |
799 textobj->m_TextState.GetFontSize(), &text_matrix, &new_matrix, | |
800 textobj->m_GraphState.GetObject(), (FX_ARGB)-1, 0, nullptr, 0); | |
801 } | |
802 } | |
803 CPDF_RenderStatus bitmap_render; | |
804 bitmap_render.Initialize(m_pContext, &bitmap_device, nullptr, m_pStopObj, | |
805 nullptr, nullptr, &m_Options, 0, m_bDropObjects, | |
806 pFormResource, TRUE); | |
807 bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix); | |
808 m_bStopped = bitmap_render.m_bStopped; | |
809 if (pSMaskDict) { | |
810 CFX_Matrix smask_matrix = *pPageObj->m_GeneralState.GetSMaskMatrix(); | |
811 smask_matrix.Concat(*pObj2Device); | |
812 std::unique_ptr<CFX_DIBSource> pSMaskSource( | |
813 LoadSMask(pSMaskDict, &rect, &smask_matrix)); | |
814 if (pSMaskSource) | |
815 bitmap->MultiplyAlpha(pSMaskSource.get()); | |
816 } | |
817 if (pTextMask) { | |
818 bitmap->MultiplyAlpha(pTextMask.get()); | |
819 pTextMask.reset(); | |
820 } | |
821 int32_t blitAlpha = 255; | |
822 if (Transparency & PDFTRANS_GROUP && group_alpha != 1.0f) { | |
823 blitAlpha = (int32_t)(group_alpha * 255); | |
824 #ifndef _SKIA_SUPPORT_ | |
825 bitmap->MultiplyAlpha(blitAlpha); | |
826 blitAlpha = 255; | |
827 #endif | |
828 } | |
829 Transparency = m_Transparency; | |
830 if (pPageObj->IsForm()) { | |
831 Transparency |= PDFTRANS_GROUP; | |
832 } | |
833 CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type, | |
834 Transparency); | |
835 #if defined _SKIA_SUPPORT_ | |
836 DebugVerifyDeviceIsPreMultiplied(); | |
837 #endif | |
838 return TRUE; | |
839 } | |
840 | |
841 CFX_DIBitmap* CPDF_RenderStatus::GetBackdrop(const CPDF_PageObject* pObj, | |
842 const FX_RECT& rect, | |
843 int& left, | |
844 int& top, | |
845 FX_BOOL bBackAlphaRequired) { | |
846 FX_RECT bbox = rect; | |
847 bbox.Intersect(m_pDevice->GetClipBox()); | |
848 left = bbox.left; | |
849 top = bbox.top; | |
850 CFX_Matrix deviceCTM = m_pDevice->GetCTM(); | |
851 FX_FLOAT scaleX = FXSYS_fabs(deviceCTM.a); | |
852 FX_FLOAT scaleY = FXSYS_fabs(deviceCTM.d); | |
853 int width = FXSYS_round(bbox.Width() * scaleX); | |
854 int height = FXSYS_round(bbox.Height() * scaleY); | |
855 std::unique_ptr<CFX_DIBitmap> pBackdrop(new CFX_DIBitmap); | |
856 if (bBackAlphaRequired && !m_bDropObjects) | |
857 pBackdrop->Create(width, height, FXDIB_Argb); | |
858 else | |
859 m_pDevice->CreateCompatibleBitmap(pBackdrop.get(), width, height); | |
860 | |
861 if (!pBackdrop->GetBuffer()) | |
862 return nullptr; | |
863 | |
864 FX_BOOL bNeedDraw; | |
865 if (pBackdrop->HasAlpha()) | |
866 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT); | |
867 else | |
868 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS); | |
869 | |
870 if (!bNeedDraw) { | |
871 m_pDevice->GetDIBits(pBackdrop.get(), left, top); | |
872 return pBackdrop.release(); | |
873 } | |
874 | |
875 CFX_Matrix FinalMatrix = m_DeviceMatrix; | |
876 FinalMatrix.TranslateI(-left, -top); | |
877 FinalMatrix.Scale(scaleX, scaleY); | |
878 pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff); | |
879 CFX_FxgeDevice device; | |
880 device.Attach(pBackdrop.get(), false, nullptr, false); | |
881 m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix); | |
882 return pBackdrop.release(); | |
883 } | |
884 | |
885 void CPDF_RenderContext::GetBackground(CFX_DIBitmap* pBuffer, | |
886 const CPDF_PageObject* pObj, | |
887 const CPDF_RenderOptions* pOptions, | |
888 CFX_Matrix* pFinalMatrix) { | |
889 CFX_FxgeDevice device; | |
890 device.Attach(pBuffer, false, nullptr, false); | |
891 | |
892 FX_RECT rect(0, 0, device.GetWidth(), device.GetHeight()); | |
893 device.FillRect(&rect, 0xffffffff); | |
894 Render(&device, pObj, pOptions, pFinalMatrix); | |
895 } | |
896 CPDF_GraphicStates* CPDF_RenderStatus::CloneObjStates( | |
897 const CPDF_GraphicStates* pSrcStates, | |
898 FX_BOOL bStroke) { | |
899 if (!pSrcStates) | |
900 return nullptr; | |
901 | |
902 CPDF_GraphicStates* pStates = new CPDF_GraphicStates; | |
903 pStates->CopyStates(*pSrcStates); | |
904 const CPDF_Color* pObjColor = bStroke | |
905 ? pSrcStates->m_ColorState.GetStrokeColor() | |
906 : pSrcStates->m_ColorState.GetFillColor(); | |
907 if (!pObjColor->IsNull()) { | |
908 pStates->m_ColorState.SetFillRGB( | |
909 bStroke ? pSrcStates->m_ColorState.GetStrokeRGB() | |
910 : pSrcStates->m_ColorState.GetFillRGB()); | |
911 pStates->m_ColorState.SetStrokeRGB(pStates->m_ColorState.GetFillRGB()); | |
912 } | |
913 return pStates; | |
914 } | |
915 | |
916 CPDF_RenderContext::CPDF_RenderContext(CPDF_Page* pPage) | |
917 : m_pDocument(pPage->m_pDocument), | |
918 m_pPageResources(pPage->m_pPageResources), | |
919 m_pPageCache(pPage->GetRenderCache()) {} | |
920 | |
921 CPDF_RenderContext::CPDF_RenderContext(CPDF_Document* pDoc, | |
922 CPDF_PageRenderCache* pPageCache) | |
923 : m_pDocument(pDoc), m_pPageResources(nullptr), m_pPageCache(pPageCache) {} | |
924 | |
925 CPDF_RenderContext::~CPDF_RenderContext() {} | |
926 | |
927 void CPDF_RenderContext::AppendLayer(CPDF_PageObjectHolder* pObjectHolder, | |
928 const CFX_Matrix* pObject2Device) { | |
929 Layer* pLayer = m_Layers.AddSpace(); | |
930 pLayer->m_pObjectHolder = pObjectHolder; | |
931 if (pObject2Device) { | |
932 pLayer->m_Matrix = *pObject2Device; | |
933 } else { | |
934 pLayer->m_Matrix.SetIdentity(); | |
935 } | |
936 } | |
937 void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, | |
938 const CPDF_RenderOptions* pOptions, | |
939 const CFX_Matrix* pLastMatrix) { | |
940 Render(pDevice, nullptr, pOptions, pLastMatrix); | |
941 } | |
942 void CPDF_RenderContext::Render(CFX_RenderDevice* pDevice, | |
943 const CPDF_PageObject* pStopObj, | |
944 const CPDF_RenderOptions* pOptions, | |
945 const CFX_Matrix* pLastMatrix) { | |
946 int count = m_Layers.GetSize(); | |
947 for (int j = 0; j < count; j++) { | |
948 pDevice->SaveState(); | |
949 Layer* pLayer = m_Layers.GetDataPtr(j); | |
950 if (pLastMatrix) { | |
951 CFX_Matrix FinalMatrix = pLayer->m_Matrix; | |
952 FinalMatrix.Concat(*pLastMatrix); | |
953 CPDF_RenderStatus status; | |
954 status.Initialize(this, pDevice, pLastMatrix, pStopObj, nullptr, nullptr, | |
955 pOptions, pLayer->m_pObjectHolder->m_Transparency, | |
956 FALSE, nullptr); | |
957 status.RenderObjectList(pLayer->m_pObjectHolder, &FinalMatrix); | |
958 if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) { | |
959 m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize); | |
960 } | |
961 if (status.m_bStopped) { | |
962 pDevice->RestoreState(false); | |
963 break; | |
964 } | |
965 } else { | |
966 CPDF_RenderStatus status; | |
967 status.Initialize(this, pDevice, nullptr, pStopObj, nullptr, nullptr, | |
968 pOptions, pLayer->m_pObjectHolder->m_Transparency, | |
969 FALSE, nullptr); | |
970 status.RenderObjectList(pLayer->m_pObjectHolder, &pLayer->m_Matrix); | |
971 if (status.m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) { | |
972 m_pPageCache->CacheOptimization(status.m_Options.m_dwLimitCacheSize); | |
973 } | |
974 if (status.m_bStopped) { | |
975 pDevice->RestoreState(false); | |
976 break; | |
977 } | |
978 } | |
979 pDevice->RestoreState(false); | |
980 } | |
981 } | |
982 | |
983 CPDF_ProgressiveRenderer::CPDF_ProgressiveRenderer( | |
984 CPDF_RenderContext* pContext, | |
985 CFX_RenderDevice* pDevice, | |
986 const CPDF_RenderOptions* pOptions) | |
987 : m_Status(Ready), | |
988 m_pContext(pContext), | |
989 m_pDevice(pDevice), | |
990 m_pOptions(pOptions), | |
991 m_LayerIndex(0), | |
992 m_pCurrentLayer(nullptr) {} | |
993 | |
994 CPDF_ProgressiveRenderer::~CPDF_ProgressiveRenderer() { | |
995 if (m_pRenderStatus) | |
996 m_pDevice->RestoreState(false); | |
997 } | |
998 | |
999 void CPDF_ProgressiveRenderer::Start(IFX_Pause* pPause) { | |
1000 if (!m_pContext || !m_pDevice || m_Status != Ready) { | |
1001 m_Status = Failed; | |
1002 return; | |
1003 } | |
1004 m_Status = ToBeContinued; | |
1005 Continue(pPause); | |
1006 } | |
1007 | |
1008 void CPDF_ProgressiveRenderer::Continue(IFX_Pause* pPause) { | |
1009 while (m_Status == ToBeContinued) { | |
1010 if (!m_pCurrentLayer) { | |
1011 if (m_LayerIndex >= m_pContext->CountLayers()) { | |
1012 m_Status = Done; | |
1013 return; | |
1014 } | |
1015 m_pCurrentLayer = m_pContext->GetLayer(m_LayerIndex); | |
1016 m_LastObjectRendered = | |
1017 m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->end(); | |
1018 m_pRenderStatus.reset(new CPDF_RenderStatus()); | |
1019 m_pRenderStatus->Initialize( | |
1020 m_pContext, m_pDevice, nullptr, nullptr, nullptr, nullptr, m_pOptions, | |
1021 m_pCurrentLayer->m_pObjectHolder->m_Transparency, FALSE, nullptr); | |
1022 m_pDevice->SaveState(); | |
1023 m_ClipRect = CFX_FloatRect(m_pDevice->GetClipBox()); | |
1024 CFX_Matrix device2object; | |
1025 device2object.SetReverse(m_pCurrentLayer->m_Matrix); | |
1026 device2object.TransformRect(m_ClipRect); | |
1027 } | |
1028 CPDF_PageObjectList::iterator iter; | |
1029 CPDF_PageObjectList::iterator iterEnd = | |
1030 m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->end(); | |
1031 if (m_LastObjectRendered != iterEnd) { | |
1032 iter = m_LastObjectRendered; | |
1033 ++iter; | |
1034 } else { | |
1035 iter = m_pCurrentLayer->m_pObjectHolder->GetPageObjectList()->begin(); | |
1036 } | |
1037 int nObjsToGo = kStepLimit; | |
1038 while (iter != iterEnd) { | |
1039 CPDF_PageObject* pCurObj = iter->get(); | |
1040 if (pCurObj && pCurObj->m_Left <= m_ClipRect.right && | |
1041 pCurObj->m_Right >= m_ClipRect.left && | |
1042 pCurObj->m_Bottom <= m_ClipRect.top && | |
1043 pCurObj->m_Top >= m_ClipRect.bottom) { | |
1044 if (m_pRenderStatus->ContinueSingleObject( | |
1045 pCurObj, &m_pCurrentLayer->m_Matrix, pPause)) { | |
1046 return; | |
1047 } | |
1048 if (pCurObj->IsImage() && | |
1049 m_pRenderStatus->m_Options.m_Flags & RENDER_LIMITEDIMAGECACHE) { | |
1050 m_pContext->GetPageCache()->CacheOptimization( | |
1051 m_pRenderStatus->m_Options.m_dwLimitCacheSize); | |
1052 } | |
1053 if (pCurObj->IsForm() || pCurObj->IsShading()) { | |
1054 nObjsToGo = 0; | |
1055 } else { | |
1056 --nObjsToGo; | |
1057 } | |
1058 } | |
1059 m_LastObjectRendered = iter; | |
1060 if (nObjsToGo == 0) { | |
1061 if (pPause && pPause->NeedToPauseNow()) | |
1062 return; | |
1063 nObjsToGo = kStepLimit; | |
1064 } | |
1065 ++iter; | |
1066 } | |
1067 if (m_pCurrentLayer->m_pObjectHolder->IsParsed()) { | |
1068 m_pRenderStatus.reset(); | |
1069 m_pDevice->RestoreState(false); | |
1070 m_pCurrentLayer = nullptr; | |
1071 m_LayerIndex++; | |
1072 if (pPause && pPause->NeedToPauseNow()) { | |
1073 return; | |
1074 } | |
1075 } else { | |
1076 m_pCurrentLayer->m_pObjectHolder->ContinueParse(pPause); | |
1077 if (!m_pCurrentLayer->m_pObjectHolder->IsParsed()) | |
1078 return; | |
1079 } | |
1080 } | |
1081 } | |
1082 | |
1083 CPDF_TransferFunc* CPDF_DocRenderData::GetTransferFunc(CPDF_Object* pObj) { | |
1084 if (!pObj) | |
1085 return nullptr; | |
1086 | |
1087 auto it = m_TransferFuncMap.find(pObj); | |
1088 if (it != m_TransferFuncMap.end()) { | |
1089 CPDF_CountedObject<CPDF_TransferFunc>* pTransferCounter = it->second; | |
1090 return pTransferCounter->AddRef(); | |
1091 } | |
1092 | |
1093 std::unique_ptr<CPDF_Function> pFuncs[3]; | |
1094 FX_BOOL bUniTransfer = TRUE; | |
1095 FX_BOOL bIdentity = TRUE; | |
1096 if (CPDF_Array* pArray = pObj->AsArray()) { | |
1097 bUniTransfer = FALSE; | |
1098 if (pArray->GetCount() < 3) | |
1099 return nullptr; | |
1100 | |
1101 for (uint32_t i = 0; i < 3; ++i) { | |
1102 pFuncs[2 - i] = CPDF_Function::Load(pArray->GetDirectObjectAt(i)); | |
1103 if (!pFuncs[2 - i]) | |
1104 return nullptr; | |
1105 } | |
1106 } else { | |
1107 pFuncs[0] = CPDF_Function::Load(pObj); | |
1108 if (!pFuncs[0]) | |
1109 return nullptr; | |
1110 } | |
1111 CPDF_TransferFunc* pTransfer = new CPDF_TransferFunc(m_pPDFDoc); | |
1112 CPDF_CountedObject<CPDF_TransferFunc>* pTransferCounter = | |
1113 new CPDF_CountedObject<CPDF_TransferFunc>(pTransfer); | |
1114 m_TransferFuncMap[pObj] = pTransferCounter; | |
1115 static const int kMaxOutputs = 16; | |
1116 FX_FLOAT output[kMaxOutputs]; | |
1117 FXSYS_memset(output, 0, sizeof(output)); | |
1118 FX_FLOAT input; | |
1119 int noutput; | |
1120 for (int v = 0; v < 256; ++v) { | |
1121 input = (FX_FLOAT)v / 255.0f; | |
1122 if (bUniTransfer) { | |
1123 if (pFuncs[0] && pFuncs[0]->CountOutputs() <= kMaxOutputs) | |
1124 pFuncs[0]->Call(&input, 1, output, noutput); | |
1125 int o = FXSYS_round(output[0] * 255); | |
1126 if (o != v) | |
1127 bIdentity = FALSE; | |
1128 for (int i = 0; i < 3; ++i) { | |
1129 pTransfer->m_Samples[i * 256 + v] = o; | |
1130 } | |
1131 } else { | |
1132 for (int i = 0; i < 3; ++i) { | |
1133 if (pFuncs[i] && pFuncs[i]->CountOutputs() <= kMaxOutputs) { | |
1134 pFuncs[i]->Call(&input, 1, output, noutput); | |
1135 int o = FXSYS_round(output[0] * 255); | |
1136 if (o != v) | |
1137 bIdentity = FALSE; | |
1138 pTransfer->m_Samples[i * 256 + v] = o; | |
1139 } else { | |
1140 pTransfer->m_Samples[i * 256 + v] = v; | |
1141 } | |
1142 } | |
1143 } | |
1144 } | |
1145 | |
1146 pTransfer->m_bIdentity = bIdentity; | |
1147 return pTransferCounter->AddRef(); | |
1148 } | |
1149 | |
1150 void CPDF_DocRenderData::ReleaseTransferFunc(CPDF_Object* pObj) { | |
1151 auto it = m_TransferFuncMap.find(pObj); | |
1152 if (it != m_TransferFuncMap.end()) | |
1153 it->second->RemoveRef(); | |
1154 } | |
1155 | |
1156 CPDF_DeviceBuffer::CPDF_DeviceBuffer() | |
1157 : m_pDevice(nullptr), m_pContext(nullptr), m_pObject(nullptr) {} | |
1158 | |
1159 CPDF_DeviceBuffer::~CPDF_DeviceBuffer() {} | |
1160 | |
1161 FX_BOOL CPDF_DeviceBuffer::Initialize(CPDF_RenderContext* pContext, | |
1162 CFX_RenderDevice* pDevice, | |
1163 FX_RECT* pRect, | |
1164 const CPDF_PageObject* pObj, | |
1165 int max_dpi) { | |
1166 m_pDevice = pDevice; | |
1167 m_pContext = pContext; | |
1168 m_Rect = *pRect; | |
1169 m_pObject = pObj; | |
1170 m_Matrix.TranslateI(-pRect->left, -pRect->top); | |
1171 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ | |
1172 int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE); | |
1173 int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE); | |
1174 if (horz_size && vert_size && max_dpi) { | |
1175 int dpih = | |
1176 pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10); | |
1177 int dpiv = | |
1178 pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10); | |
1179 if (dpih > max_dpi) { | |
1180 m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f); | |
1181 } | |
1182 if (dpiv > max_dpi) { | |
1183 m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv); | |
1184 } | |
1185 } | |
1186 #endif | |
1187 CFX_Matrix ctm = m_pDevice->GetCTM(); | |
1188 FX_FLOAT fScaleX = FXSYS_fabs(ctm.a); | |
1189 FX_FLOAT fScaleY = FXSYS_fabs(ctm.d); | |
1190 m_Matrix.Concat(fScaleX, 0, 0, fScaleY, 0, 0); | |
1191 CFX_FloatRect rect(*pRect); | |
1192 m_Matrix.TransformRect(rect); | |
1193 FX_RECT bitmap_rect = rect.GetOuterRect(); | |
1194 m_pBitmap.reset(new CFX_DIBitmap); | |
1195 m_pBitmap->Create(bitmap_rect.Width(), bitmap_rect.Height(), FXDIB_Argb); | |
1196 return TRUE; | |
1197 } | |
1198 void CPDF_DeviceBuffer::OutputToDevice() { | |
1199 if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) { | |
1200 if (m_Matrix.a == 1.0f && m_Matrix.d == 1.0f) { | |
1201 m_pDevice->SetDIBits(m_pBitmap.get(), m_Rect.left, m_Rect.top); | |
1202 } else { | |
1203 m_pDevice->StretchDIBits(m_pBitmap.get(), m_Rect.left, m_Rect.top, | |
1204 m_Rect.Width(), m_Rect.Height()); | |
1205 } | |
1206 } else { | |
1207 CFX_DIBitmap buffer; | |
1208 m_pDevice->CreateCompatibleBitmap(&buffer, m_pBitmap->GetWidth(), | |
1209 m_pBitmap->GetHeight()); | |
1210 m_pContext->GetBackground(&buffer, m_pObject, nullptr, &m_Matrix); | |
1211 buffer.CompositeBitmap(0, 0, buffer.GetWidth(), buffer.GetHeight(), | |
1212 m_pBitmap.get(), 0, 0); | |
1213 m_pDevice->StretchDIBits(&buffer, m_Rect.left, m_Rect.top, m_Rect.Width(), | |
1214 m_Rect.Height()); | |
1215 } | |
1216 } | |
1217 | |
1218 CPDF_ScaledRenderBuffer::CPDF_ScaledRenderBuffer() {} | |
1219 | |
1220 CPDF_ScaledRenderBuffer::~CPDF_ScaledRenderBuffer() {} | |
1221 | |
1222 #define _FPDFAPI_IMAGESIZE_LIMIT_ (30 * 1024 * 1024) | |
1223 FX_BOOL CPDF_ScaledRenderBuffer::Initialize(CPDF_RenderContext* pContext, | |
1224 CFX_RenderDevice* pDevice, | |
1225 const FX_RECT& pRect, | |
1226 const CPDF_PageObject* pObj, | |
1227 const CPDF_RenderOptions* pOptions, | |
1228 int max_dpi) { | |
1229 m_pDevice = pDevice; | |
1230 if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_GET_BITS) { | |
1231 return TRUE; | |
1232 } | |
1233 m_pContext = pContext; | |
1234 m_Rect = pRect; | |
1235 m_pObject = pObj; | |
1236 m_Matrix.TranslateI(-pRect.left, -pRect.top); | |
1237 int horz_size = pDevice->GetDeviceCaps(FXDC_HORZ_SIZE); | |
1238 int vert_size = pDevice->GetDeviceCaps(FXDC_VERT_SIZE); | |
1239 if (horz_size && vert_size && max_dpi) { | |
1240 int dpih = | |
1241 pDevice->GetDeviceCaps(FXDC_PIXEL_WIDTH) * 254 / (horz_size * 10); | |
1242 int dpiv = | |
1243 pDevice->GetDeviceCaps(FXDC_PIXEL_HEIGHT) * 254 / (vert_size * 10); | |
1244 if (dpih > max_dpi) { | |
1245 m_Matrix.Scale((FX_FLOAT)(max_dpi) / dpih, 1.0f); | |
1246 } | |
1247 if (dpiv > max_dpi) { | |
1248 m_Matrix.Scale(1.0f, (FX_FLOAT)(max_dpi) / (FX_FLOAT)dpiv); | |
1249 } | |
1250 } | |
1251 m_pBitmapDevice.reset(new CFX_FxgeDevice); | |
1252 FXDIB_Format dibFormat = FXDIB_Rgb; | |
1253 int32_t bpp = 24; | |
1254 if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_ALPHA_OUTPUT) { | |
1255 dibFormat = FXDIB_Argb; | |
1256 bpp = 32; | |
1257 } | |
1258 while (1) { | |
1259 CFX_FloatRect rect(pRect); | |
1260 m_Matrix.TransformRect(rect); | |
1261 FX_RECT bitmap_rect = rect.GetOuterRect(); | |
1262 int32_t iWidth = bitmap_rect.Width(); | |
1263 int32_t iHeight = bitmap_rect.Height(); | |
1264 int32_t iPitch = (iWidth * bpp + 31) / 32 * 4; | |
1265 if (iWidth * iHeight < 1) | |
1266 return FALSE; | |
1267 | |
1268 if (iPitch * iHeight <= _FPDFAPI_IMAGESIZE_LIMIT_ && | |
1269 m_pBitmapDevice->Create(iWidth, iHeight, dibFormat, nullptr)) { | |
1270 break; | |
1271 } | |
1272 m_Matrix.Scale(0.5f, 0.5f); | |
1273 } | |
1274 m_pContext->GetBackground(m_pBitmapDevice->GetBitmap(), m_pObject, pOptions, | |
1275 &m_Matrix); | |
1276 return TRUE; | |
1277 } | |
1278 void CPDF_ScaledRenderBuffer::OutputToDevice() { | |
1279 if (m_pBitmapDevice) { | |
1280 m_pDevice->StretchDIBits(m_pBitmapDevice->GetBitmap(), m_Rect.left, | |
1281 m_Rect.top, m_Rect.Width(), m_Rect.Height()); | |
1282 } | |
1283 } | |
1284 | |
1285 #if defined _SKIA_SUPPORT_ | |
1286 void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const { | |
1287 m_pDevice->DebugVerifyBitmapIsPreMultiplied(); | |
1288 } | |
1289 #endif | |
OLD | NEW |