Revert "FX Bool considered harmful, part 3"
[pdfium.git] / core / src / fpdfapi / fpdf_render / fpdf_render_image.cpp
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/fpdfapi/fpdf_module.h"
8 #include "../../../include/fpdfapi/fpdf_pageobj.h"
9 #include "../../../include/fpdfapi/fpdf_render.h"
10 #include "../../../include/fxcodec/fx_codec.h"
11 #include "../../../include/fxcrt/fx_safe_types.h"
12 #include "../../../include/fxge/fx_ge.h"
13 #include "../fpdf_page/pageint.h"
14 #include "render_int.h"
15
16 FX_BOOL CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj, const CFX_AffineMatrix* pObj2Device)
17 {
18     CPDF_ImageRenderer render;
19     if (render.Start(this, pImageObj, pObj2Device, m_bStdCS, m_curBlend)) {
20         render.Continue(NULL);
21     }
22     return render.m_Result;
23 }
24 void CPDF_RenderStatus::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap, int left, int top, FX_ARGB mask_argb,
25         int bitmap_alpha, int blend_mode, int Transparency)
26 {
27     if (pDIBitmap == NULL) {
28         return;
29     }
30     FX_BOOL bIsolated = Transparency & PDFTRANS_ISOLATED;
31     FX_BOOL bGroup = Transparency & PDFTRANS_GROUP;
32     if (blend_mode == FXDIB_BLEND_NORMAL) {
33         if (!pDIBitmap->IsAlphaMask()) {
34             if (bitmap_alpha < 255) {
35                 pDIBitmap->MultiplyAlpha(bitmap_alpha);
36             }
37             if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
38                 return;
39             }
40         } else {
41             FX_DWORD fill_argb = m_Options.TranslateColor(mask_argb);
42             if (bitmap_alpha < 255) {
43                 ((uint8_t*)&fill_argb)[3] = ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255;
44             }
45             if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
46                 return;
47             }
48         }
49     }
50     FX_BOOL bBackAlphaRequired = blend_mode && bIsolated && !m_bDropObjects;
51     FX_BOOL bGetBackGround = ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
52                              (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) && (m_pDevice->GetRenderCaps()
53                                      & FXRC_GET_BITS) && !bBackAlphaRequired);
54     if (bGetBackGround) {
55         if (bIsolated || !bGroup) {
56             if (pDIBitmap->IsAlphaMask()) {
57                 return;
58             }
59             m_pDevice->SetDIBits(pDIBitmap, left, top, blend_mode);
60         } else {
61             FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), top + pDIBitmap->GetHeight());
62             rect.Intersect(m_pDevice->GetClipBox());
63             CFX_DIBitmap* pClone = NULL;
64             FX_BOOL bClone = FALSE;
65             if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
66                 bClone = TRUE;
67                 pClone = m_pDevice->GetBackDrop()->Clone(&rect);
68                 CFX_DIBitmap *pForeBitmap = m_pDevice->GetBitmap();
69                 pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), pForeBitmap, rect.left, rect.top);
70                 left = left >= 0 ? 0 : left;
71                 top = top >= 0 ? 0 : top;
72                 if (!pDIBitmap->IsAlphaMask())
73                     pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), pDIBitmap,
74                                             left, top, blend_mode);
75                 else
76                     pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(), pDIBitmap,
77                                           mask_argb, left, top, blend_mode);
78             } else {
79                 pClone = pDIBitmap;
80             }
81             if (m_pDevice->GetBackDrop()) {
82                 m_pDevice->SetDIBits(pClone, rect.left, rect.top);
83             } else {
84                 if (pDIBitmap->IsAlphaMask()) {
85                     return;
86                 }
87                 m_pDevice->SetDIBits(pDIBitmap, rect.left, rect.top, blend_mode);
88             }
89             if (bClone) {
90                 delete pClone;
91             }
92         }
93         return;
94     }
95     int back_left, back_top;
96     FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), top + pDIBitmap->GetHeight());
97     CFX_DIBitmap* pBackdrop = GetBackdrop(m_pCurObj, rect, back_left, back_top, blend_mode > FXDIB_BLEND_NORMAL && bIsolated);
98     if (!pBackdrop) {
99         return;
100     }
101     if (!pDIBitmap->IsAlphaMask())
102         pBackdrop->CompositeBitmap(left - back_left, top - back_top, pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), pDIBitmap,
103                                    0, 0, blend_mode);
104     else
105         pBackdrop->CompositeMask(left - back_left, top - back_top, pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), pDIBitmap,
106                                  mask_argb, 0, 0, blend_mode);
107     CFX_DIBitmap* pBackdrop1 = new CFX_DIBitmap;
108     pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(), FXDIB_Rgb32);
109     pBackdrop1->Clear((FX_DWORD) - 1);
110     pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(), pBackdrop->GetHeight(), pBackdrop, 0, 0);
111     delete pBackdrop;
112     pBackdrop = pBackdrop1;
113     m_pDevice->SetDIBits(pBackdrop, back_left, back_top);
114     delete pBackdrop;
115 }
116 FX_COLORREF CPDF_TransferFunc::TranslateColor(FX_COLORREF rgb)
117 {
118     return FXSYS_RGB(m_Samples[FXSYS_GetRValue(rgb)], m_Samples[256 + FXSYS_GetGValue(rgb)],
119                      m_Samples[512 + FXSYS_GetBValue(rgb)]);
120 }
121 CFX_DIBSource* CPDF_TransferFunc::TranslateImage(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc)
122 {
123     CPDF_DIBTransferFunc* pDest = new CPDF_DIBTransferFunc(this);
124     pDest->LoadSrc(pSrc, bAutoDropSrc);
125     return pDest;
126 }
127 FXDIB_Format CPDF_DIBTransferFunc::GetDestFormat()
128 {
129     if (m_pSrc->IsAlphaMask()) {
130         return FXDIB_8bppMask;
131     }
132 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
133     return (m_pSrc->HasAlpha()) ? FXDIB_Argb : FXDIB_Rgb32;
134 #else
135     return (m_pSrc->HasAlpha()) ? FXDIB_Argb : FXDIB_Rgb;
136 #endif
137 }
138 CPDF_DIBTransferFunc::CPDF_DIBTransferFunc(const CPDF_TransferFunc* pTransferFunc)
139 {
140     m_RampR = pTransferFunc->m_Samples;
141     m_RampG = &pTransferFunc->m_Samples[256];
142     m_RampB = &pTransferFunc->m_Samples[512];
143 }
144 void CPDF_DIBTransferFunc::TranslateScanline(uint8_t* dest_buf, const uint8_t* src_buf) const
145 {
146     int i;
147     FX_BOOL bSkip = FALSE;
148     switch (m_pSrc->GetFormat()) {
149         case FXDIB_1bppRgb: {
150                 int r0 = m_RampR[0], g0 = m_RampG[0], b0 = m_RampB[0];
151                 int r1 = m_RampR[255], g1 = m_RampG[255], b1 = m_RampB[255];
152                 for (i = 0; i < m_Width; i ++) {
153                     if (src_buf[i / 8] & (1 << (7 - i % 8))) {
154                         *dest_buf++ = b1;
155                         *dest_buf++ = g1;
156                         *dest_buf++ = r1;
157                     } else {
158                         *dest_buf++ = b0;
159                         *dest_buf++ = g0;
160                         *dest_buf++ = r0;
161                     }
162 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
163                     dest_buf++;
164 #endif
165                 }
166                 break;
167             }
168         case FXDIB_1bppMask: {
169                 int m0 = m_RampR[0], m1 = m_RampR[255];
170                 for (i = 0; i < m_Width; i ++) {
171                     if (src_buf[i / 8] & (1 << (7 - i % 8))) {
172                         *dest_buf++ = m1;
173                     } else {
174                         *dest_buf++ = m0;
175                     }
176                 }
177                 break;
178             }
179         case FXDIB_8bppRgb: {
180                 FX_ARGB* pPal = m_pSrc->GetPalette();
181                 for (i = 0; i < m_Width; i ++) {
182                     if (pPal) {
183                         FX_ARGB src_argb = pPal[*src_buf];
184                         *dest_buf++ = m_RampB[FXARGB_R(src_argb)];
185                         *dest_buf++ = m_RampG[FXARGB_G(src_argb)];
186                         *dest_buf++ = m_RampR[FXARGB_B(src_argb)];
187                     } else {
188                         FX_DWORD src_byte = *src_buf;
189                         *dest_buf++ = m_RampB[src_byte];
190                         *dest_buf++ = m_RampG[src_byte];
191                         *dest_buf++ = m_RampR[src_byte];
192                     }
193                     src_buf ++;
194 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
195                     dest_buf++;
196 #endif
197                 }
198                 break;
199             }
200         case FXDIB_8bppMask:
201             for (i = 0; i < m_Width; i ++) {
202                 *dest_buf++ = m_RampR[*(src_buf++)];
203             }
204             break;
205         case FXDIB_Rgb:
206             for (i = 0; i < m_Width; i ++) {
207                 *dest_buf++ = m_RampB[*(src_buf++)];
208                 *dest_buf++ = m_RampG[*(src_buf++)];
209                 *dest_buf++ = m_RampR[*(src_buf++)];
210 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
211                 dest_buf++;
212 #endif
213             }
214             break;
215         case FXDIB_Rgb32:
216             bSkip = TRUE;
217         case FXDIB_Argb:
218             for (i = 0; i < m_Width; i ++) {
219                 *dest_buf++ = m_RampB[*(src_buf++)];
220                 *dest_buf++ = m_RampG[*(src_buf++)];
221                 *dest_buf++ = m_RampR[*(src_buf++)];
222                 if (!bSkip) {
223                     *dest_buf++ = *src_buf;
224                 }
225 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
226                 else {
227                     dest_buf++;
228                 }
229 #endif
230                 src_buf ++;
231             }
232             break;
233         default:
234             break;
235     }
236 }
237 void CPDF_DIBTransferFunc::TranslateDownSamples(uint8_t* dest_buf, const uint8_t* src_buf, int pixels, int Bpp) const
238 {
239     if (Bpp == 8) {
240         for (int i = 0; i < pixels; i ++) {
241             *dest_buf++ = m_RampR[*(src_buf++)];
242         }
243     } else if (Bpp == 24) {
244         for (int i = 0; i < pixels; i ++) {
245             *dest_buf++ = m_RampB[*(src_buf++)];
246             *dest_buf++ = m_RampG[*(src_buf++)];
247             *dest_buf++ = m_RampR[*(src_buf++)];
248         }
249     } else {
250 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
251         if (!m_pSrc->HasAlpha()) {
252             for (int i = 0; i < pixels; i ++) {
253                 *dest_buf++ = m_RampB[*(src_buf++)];
254                 *dest_buf++ = m_RampG[*(src_buf++)];
255                 *dest_buf++ = m_RampR[*(src_buf++)];
256                 dest_buf++;
257                 src_buf++;
258             }
259         } else
260 #endif
261             for (int i = 0; i < pixels; i ++) {
262                 *dest_buf++ = m_RampB[*(src_buf++)];
263                 *dest_buf++ = m_RampG[*(src_buf++)];
264                 *dest_buf++ = m_RampR[*(src_buf++)];
265                 *dest_buf++ = *(src_buf++);
266             }
267     }
268 }
269 static FX_BOOL _IsSupported(CPDF_ColorSpace* pCS)
270 {
271     if (pCS->GetFamily() == PDFCS_DEVICERGB || pCS->GetFamily() == PDFCS_DEVICEGRAY ||
272             pCS->GetFamily() == PDFCS_DEVICECMYK || pCS->GetFamily() == PDFCS_CALGRAY ||
273             pCS->GetFamily() == PDFCS_CALRGB) {
274         return TRUE;
275     }
276     if (pCS->GetFamily() == PDFCS_INDEXED && _IsSupported(pCS->GetBaseCS())) {
277         return TRUE;
278     }
279     return FALSE;
280 }
281 CPDF_ImageRenderer::CPDF_ImageRenderer()
282 {
283     m_pRenderStatus = NULL;
284     m_pImageObject = NULL;
285     m_Result = TRUE;
286     m_Status = 0;
287     m_pQuickStretcher = NULL;
288     m_pTransformer = NULL;
289     m_DeviceHandle = NULL;
290     m_LoadHandle = NULL;
291     m_pClone = NULL;
292     m_bStdCS = FALSE;
293     m_bPatternColor = FALSE;
294     m_BlendType = FXDIB_BLEND_NORMAL;
295     m_pPattern = NULL;
296     m_pObj2Device = NULL;
297 }
298 CPDF_ImageRenderer::~CPDF_ImageRenderer()
299 {
300     delete m_pQuickStretcher;
301     delete m_pTransformer;
302     if (m_DeviceHandle) {
303         m_pRenderStatus->m_pDevice->CancelDIBits(m_DeviceHandle);
304     }
305     delete (CPDF_ProgressiveImageLoaderHandle*)m_LoadHandle;
306     delete m_pClone;
307 }
308 FX_BOOL CPDF_ImageRenderer::StartLoadDIBSource()
309 {
310     CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
311     FX_RECT image_rect = image_rect_f.GetOutterRect();
312     int dest_width = image_rect.Width();
313     int dest_height = image_rect.Height();
314     if (m_ImageMatrix.a < 0) {
315         dest_width = -dest_width;
316     }
317     if (m_ImageMatrix.d > 0) {
318         dest_height = -dest_height;
319     }
320     if (m_Loader.StartLoadImage(m_pImageObject, m_pRenderStatus->m_pContext->m_pPageCache, m_LoadHandle, m_bStdCS,
321                                 m_pRenderStatus->m_GroupFamily, m_pRenderStatus->m_bLoadMask, m_pRenderStatus, dest_width, dest_height)) {
322         if (m_LoadHandle != NULL) {
323             m_Status = 4;
324             return TRUE;
325         }
326         return FALSE;
327     }
328     return FALSE;
329 }
330 FX_BOOL CPDF_ImageRenderer::StartRenderDIBSource()
331 {
332     if (m_Loader.m_pBitmap == NULL) {
333         return FALSE;
334     }
335     m_BitmapAlpha = 255;
336     const CPDF_GeneralStateData* pGeneralState = m_pImageObject->m_GeneralState;
337     if (pGeneralState) {
338         m_BitmapAlpha = FXSYS_round(pGeneralState->m_FillAlpha * 255);
339     }
340     m_pDIBSource = m_Loader.m_pBitmap;
341     if (m_pRenderStatus->m_Options.m_ColorMode == RENDER_COLOR_ALPHA && m_Loader.m_pMask == NULL) {
342         return StartBitmapAlpha();
343     }
344     if (pGeneralState && pGeneralState->m_pTR) {
345         if (!pGeneralState->m_pTransferFunc) {
346             ((CPDF_GeneralStateData*)pGeneralState)->m_pTransferFunc = m_pRenderStatus->GetTransferFunc(pGeneralState->m_pTR);
347         }
348         if (pGeneralState->m_pTransferFunc && !pGeneralState->m_pTransferFunc->m_bIdentity) {
349             m_pDIBSource = m_Loader.m_pBitmap = pGeneralState->m_pTransferFunc->TranslateImage(m_Loader.m_pBitmap, !m_Loader.m_bCached);
350             if (m_Loader.m_bCached && m_Loader.m_pMask) {
351                 m_Loader.m_pMask = m_Loader.m_pMask->Clone();
352             }
353             m_Loader.m_bCached = FALSE;
354         }
355     }
356     m_FillArgb = 0;
357     m_bPatternColor = FALSE;
358     m_pPattern = NULL;
359     if (m_pDIBSource->IsAlphaMask()) {
360         CPDF_Color* pColor = m_pImageObject->m_ColorState.GetFillColor();
361         if (pColor && pColor->IsPattern()) {
362             m_pPattern = pColor->GetPattern();
363             if (m_pPattern != NULL) {
364                 m_bPatternColor = TRUE;
365             }
366         }
367         m_FillArgb = m_pRenderStatus->GetFillArgb(m_pImageObject);
368     } else if (m_pRenderStatus->m_Options.m_ColorMode == RENDER_COLOR_GRAY) {
369         m_pClone = m_pDIBSource->Clone();
370         m_pClone->ConvertColorScale(m_pRenderStatus->m_Options.m_BackColor, m_pRenderStatus->m_Options.m_ForeColor);
371         m_pDIBSource = m_pClone;
372     }
373     m_Flags = 0;
374     if (m_pRenderStatus->m_Options.m_Flags & RENDER_FORCE_DOWNSAMPLE) {
375         m_Flags |= RENDER_FORCE_DOWNSAMPLE;
376     } else if (m_pRenderStatus->m_Options.m_Flags & RENDER_FORCE_HALFTONE) {
377         m_Flags |= RENDER_FORCE_HALFTONE;
378     }
379     if (m_pRenderStatus->m_pDevice->GetDeviceClass() != FXDC_DISPLAY) {
380         CPDF_Object* pFilters = m_pImageObject->m_pImage->GetStream()->GetDict()->GetElementValue(FX_BSTRC("Filter"));
381         if (pFilters) {
382             if (pFilters->GetType() == PDFOBJ_NAME) {
383                 CFX_ByteStringC bsDecodeType = pFilters->GetConstString();
384                 if (bsDecodeType == FX_BSTRC("DCTDecode") || bsDecodeType == FX_BSTRC("JPXDecode")) {
385                     m_Flags |= FXRENDER_IMAGE_LOSSY;
386                 }
387             } else if (pFilters->GetType() == PDFOBJ_ARRAY) {
388                 CPDF_Array* pArray = (CPDF_Array*)pFilters;
389                 for (FX_DWORD i = 0; i < pArray->GetCount(); i ++) {
390                     CFX_ByteStringC bsDecodeType = pArray->GetConstString(i);
391                     if (bsDecodeType == FX_BSTRC("DCTDecode") || bsDecodeType == FX_BSTRC("JPXDecode")) {
392                         m_Flags |= FXRENDER_IMAGE_LOSSY;
393                         break;
394                     }
395                 }
396             }
397         }
398     }
399     if (m_pRenderStatus->m_Options.m_Flags & RENDER_NOIMAGESMOOTH) {
400         m_Flags |= FXDIB_NOSMOOTH;
401     } else if (m_pImageObject->m_pImage->IsInterpol()) {
402         m_Flags |= FXDIB_INTERPOL;
403     }
404     if (m_Loader.m_pMask) {
405         return DrawMaskedImage();
406     }
407     if (m_bPatternColor) {
408         return DrawPatternImage(m_pObj2Device);
409     }
410     if (m_BitmapAlpha == 255 && pGeneralState && pGeneralState->m_FillOP &&
411             pGeneralState->m_OPMode == 0 && pGeneralState->m_BlendType == FXDIB_BLEND_NORMAL && pGeneralState->m_StrokeAlpha == 1 && pGeneralState->m_FillAlpha == 1) {
412         CPDF_Document* pDocument = NULL;
413         CPDF_Page* pPage = NULL;
414         if (m_pRenderStatus->m_pContext->m_pPageCache) {
415             pPage = m_pRenderStatus->m_pContext->m_pPageCache->GetPage();
416             pDocument = pPage->m_pDocument;
417         } else {
418             pDocument = m_pImageObject->m_pImage->GetDocument();
419         }
420         CPDF_Dictionary* pPageResources = pPage ? pPage->m_pPageResources : NULL;
421         CPDF_Object* pCSObj = m_pImageObject->m_pImage->GetStream()->GetDict()->GetElementValue(FX_BSTRC("ColorSpace"));
422         CPDF_ColorSpace* pColorSpace = pDocument->LoadColorSpace(pCSObj, pPageResources);
423         if (pColorSpace) {
424             int format = pColorSpace->GetFamily();
425             if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || format == PDFCS_DEVICEN) {
426                 m_BlendType = FXDIB_BLEND_DARKEN;
427             }
428             pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
429         }
430     }
431     return StartDIBSource();
432 }
433 FX_BOOL CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus, const CPDF_PageObject* pObj, const CFX_AffineMatrix* pObj2Device, FX_BOOL bStdCS, int blendType)
434 {
435     m_pRenderStatus = pStatus;
436     m_bStdCS = bStdCS;
437     m_pImageObject = (CPDF_ImageObject*)pObj;
438     m_BlendType = blendType;
439     m_pObj2Device = pObj2Device;
440     CPDF_Dictionary* pOC = m_pImageObject->m_pImage->GetOC();
441     if (pOC && m_pRenderStatus->m_Options.m_pOCContext && !m_pRenderStatus->m_Options.m_pOCContext->CheckOCGVisible(pOC)) {
442         return FALSE;
443     }
444     m_ImageMatrix = m_pImageObject->m_Matrix;
445     m_ImageMatrix.Concat(*pObj2Device);
446     if (StartLoadDIBSource()) {
447         return TRUE;
448     }
449     return StartRenderDIBSource();
450 }
451 FX_BOOL CPDF_ImageRenderer::Start(CPDF_RenderStatus* pStatus, const CFX_DIBSource* pDIBSource, FX_ARGB bitmap_argb,
452                                   int bitmap_alpha, const CFX_AffineMatrix* pImage2Device, FX_DWORD flags, FX_BOOL bStdCS, int blendType)
453 {
454     m_pRenderStatus = pStatus;
455     m_pDIBSource = pDIBSource;
456     m_FillArgb = bitmap_argb;
457     m_BitmapAlpha = bitmap_alpha;
458     m_ImageMatrix = *pImage2Device;
459     m_Flags = flags;
460     m_bStdCS = bStdCS;
461     m_BlendType = blendType;
462     return StartDIBSource();
463 }
464 FX_BOOL CPDF_ImageRenderer::DrawPatternImage(const CFX_Matrix* pObj2Device)
465 {
466     if (m_pRenderStatus->m_bPrint && !(m_pRenderStatus->m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
467         m_Result = FALSE;
468         return FALSE;
469     }
470     FX_RECT rect = m_ImageMatrix.GetUnitRect().GetOutterRect();
471     rect.Intersect(m_pRenderStatus->m_pDevice->GetClipBox());
472     if (rect.IsEmpty()) {
473         return FALSE;
474     }
475     CFX_AffineMatrix new_matrix = m_ImageMatrix;
476     new_matrix.TranslateI(-rect.left, -rect.top);
477     int width = rect.Width();
478     int height = rect.Height();
479     CFX_FxgeDevice bitmap_device1;
480     if (!bitmap_device1.Create(rect.Width(), rect.Height(), FXDIB_Rgb32)) {
481         return TRUE;
482     }
483     bitmap_device1.GetBitmap()->Clear(0xffffff);
484     {
485         CPDF_RenderStatus bitmap_render;
486         bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device1, NULL, NULL,
487                                  NULL, NULL, &m_pRenderStatus->m_Options, 0, m_pRenderStatus->m_bDropObjects, NULL, TRUE);
488         CFX_Matrix patternDevice = *pObj2Device;
489         patternDevice.Translate((FX_FLOAT) - rect.left, (FX_FLOAT) - rect.top);
490         if(m_pPattern->m_PatternType == PATTERN_TILING) {
491             bitmap_render.DrawTilingPattern((CPDF_TilingPattern*)m_pPattern, m_pImageObject, &patternDevice, FALSE);
492         } else {
493             bitmap_render.DrawShadingPattern((CPDF_ShadingPattern*)m_pPattern, m_pImageObject, &patternDevice, FALSE);
494         }
495     }
496     {
497         CFX_FxgeDevice bitmap_device2;
498         if (!bitmap_device2.Create(rect.Width(), rect.Height(), FXDIB_8bppRgb)) {
499             return TRUE;
500         }
501         bitmap_device2.GetBitmap()->Clear(0);
502         CPDF_RenderStatus bitmap_render;
503         bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device2, NULL, NULL,
504                                  NULL, NULL, NULL, 0, m_pRenderStatus->m_bDropObjects, NULL, TRUE);
505         CPDF_ImageRenderer image_render;
506         if (image_render.Start(&bitmap_render, m_pDIBSource, 0xffffffff, 255, &new_matrix, m_Flags, TRUE)) {
507             image_render.Continue(NULL);
508         }
509         if (m_Loader.m_MatteColor != 0xffffffff) {
510             int matte_r = FXARGB_R(m_Loader.m_MatteColor);
511             int matte_g = FXARGB_G(m_Loader.m_MatteColor);
512             int matte_b = FXARGB_B(m_Loader.m_MatteColor);
513             for (int row = 0; row < height; row ++) {
514                 uint8_t* dest_scan = (uint8_t*)bitmap_device1.GetBitmap()->GetScanline(row);
515                 const uint8_t* mask_scan = bitmap_device2.GetBitmap()->GetScanline(row);
516                 for (int col = 0; col < width; col ++) {
517                     int alpha = *mask_scan ++;
518                     if (alpha) {
519                         int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
520                         if (orig < 0) {
521                             orig = 0;
522                         } else if (orig > 255) {
523                             orig = 255;
524                         }
525                         *dest_scan++ = orig;
526                         orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
527                         if (orig < 0) {
528                             orig = 0;
529                         } else if (orig > 255) {
530                             orig = 255;
531                         }
532                         *dest_scan++ = orig;
533                         orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
534                         if (orig < 0) {
535                             orig = 0;
536                         } else if (orig > 255) {
537                             orig = 255;
538                         }
539                         *dest_scan++ = orig;
540                         dest_scan ++;
541                     } else {
542                         dest_scan += 4;
543                     }
544                 }
545             }
546         }
547         bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
548         bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
549         bitmap_device1.GetBitmap()->MultiplyAlpha(255);
550     }
551     m_pRenderStatus->m_pDevice->SetDIBits(bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
552     return FALSE;
553 }
554 FX_BOOL CPDF_ImageRenderer::DrawMaskedImage()
555 {
556     if (m_pRenderStatus->m_bPrint && !(m_pRenderStatus->m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
557         m_Result = FALSE;
558         return FALSE;
559     }
560     FX_RECT rect = m_ImageMatrix.GetUnitRect().GetOutterRect();
561     rect.Intersect(m_pRenderStatus->m_pDevice->GetClipBox());
562     if (rect.IsEmpty()) {
563         return FALSE;
564     }
565     CFX_AffineMatrix new_matrix = m_ImageMatrix;
566     new_matrix.TranslateI(-rect.left, -rect.top);
567     int width = rect.Width();
568     int height = rect.Height();
569     CFX_FxgeDevice bitmap_device1;
570     if (!bitmap_device1.Create(width, height, FXDIB_Rgb32)) {
571         return TRUE;
572     }
573     bitmap_device1.GetBitmap()->Clear(0xffffff);
574     {
575         CPDF_RenderStatus bitmap_render;
576         bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device1, NULL, NULL,
577                                  NULL, NULL, NULL, 0, m_pRenderStatus->m_bDropObjects, NULL, TRUE);
578         CPDF_ImageRenderer image_render;
579         if (image_render.Start(&bitmap_render, m_pDIBSource, 0, 255, &new_matrix, m_Flags, TRUE)) {
580             image_render.Continue(NULL);
581         }
582     }
583     {
584         CFX_FxgeDevice bitmap_device2;
585         if (!bitmap_device2.Create(width, height, FXDIB_8bppRgb)) {
586             return TRUE;
587         }
588         bitmap_device2.GetBitmap()->Clear(0);
589         CPDF_RenderStatus bitmap_render;
590         bitmap_render.Initialize(m_pRenderStatus->m_pContext, &bitmap_device2, NULL, NULL,
591                                  NULL, NULL, NULL, 0, m_pRenderStatus->m_bDropObjects, NULL, TRUE);
592         CPDF_ImageRenderer image_render;
593         if (image_render.Start(&bitmap_render, m_Loader.m_pMask, 0xffffffff, 255, &new_matrix, m_Flags, TRUE)) {
594             image_render.Continue(NULL);
595         }
596         if (m_Loader.m_MatteColor != 0xffffffff) {
597             int matte_r = FXARGB_R(m_Loader.m_MatteColor);
598             int matte_g = FXARGB_G(m_Loader.m_MatteColor);
599             int matte_b = FXARGB_B(m_Loader.m_MatteColor);
600             for (int row = 0; row < height; row ++) {
601                 uint8_t* dest_scan = (uint8_t*)bitmap_device1.GetBitmap()->GetScanline(row);
602                 const uint8_t* mask_scan = bitmap_device2.GetBitmap()->GetScanline(row);
603                 for (int col = 0; col < width; col ++) {
604                     int alpha = *mask_scan ++;
605                     if (alpha) {
606                         int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
607                         if (orig < 0) {
608                             orig = 0;
609                         } else if (orig > 255) {
610                             orig = 255;
611                         }
612                         *dest_scan++ = orig;
613                         orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
614                         if (orig < 0) {
615                             orig = 0;
616                         } else if (orig > 255) {
617                             orig = 255;
618                         }
619                         *dest_scan++ = orig;
620                         orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
621                         if (orig < 0) {
622                             orig = 0;
623                         } else if (orig > 255) {
624                             orig = 255;
625                         }
626                         *dest_scan++ = orig;
627                         dest_scan ++;
628                     } else {
629                         dest_scan += 4;
630                     }
631                 }
632             }
633         }
634         bitmap_device2.GetBitmap()->ConvertFormat(FXDIB_8bppMask);
635         bitmap_device1.GetBitmap()->MultiplyAlpha(bitmap_device2.GetBitmap());
636         if (m_BitmapAlpha < 255) {
637             bitmap_device1.GetBitmap()->MultiplyAlpha(m_BitmapAlpha);
638         }
639     }
640     m_pRenderStatus->m_pDevice->SetDIBits(bitmap_device1.GetBitmap(), rect.left, rect.top, m_BlendType);
641     return FALSE;
642 }
643 FX_BOOL CPDF_ImageRenderer::StartDIBSource()
644 {
645     if (!(m_Flags & RENDER_FORCE_DOWNSAMPLE) && m_pDIBSource->GetBPP() > 1) {
646         int image_size = m_pDIBSource->GetBPP() / 8 * m_pDIBSource->GetWidth() * m_pDIBSource->GetHeight();
647         if (image_size > FPDF_HUGE_IMAGE_SIZE && !(m_Flags & RENDER_FORCE_HALFTONE)) {
648             m_Flags |= RENDER_FORCE_DOWNSAMPLE;
649         }
650     }
651     if (m_pRenderStatus->m_pDevice->StartDIBits(m_pDIBSource, m_BitmapAlpha, m_FillArgb,
652             &m_ImageMatrix, m_Flags, m_DeviceHandle, 0, NULL, m_BlendType)) {
653         if (m_DeviceHandle != NULL) {
654             m_Status = 3;
655             return TRUE;
656         }
657         return FALSE;
658     }
659     CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
660     FX_RECT image_rect = image_rect_f.GetOutterRect();
661     int dest_width = image_rect.Width();
662     int dest_height = image_rect.Height();
663     if ((FXSYS_fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
664             (FXSYS_fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0) ) {
665         if (m_pRenderStatus->m_bPrint && !(m_pRenderStatus->m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
666             m_Result = FALSE;
667             return FALSE;
668         }
669         FX_RECT clip_box = m_pRenderStatus->m_pDevice->GetClipBox();
670         clip_box.Intersect(image_rect);
671         m_Status = 2;
672         m_pTransformer = new CFX_ImageTransformer;
673         m_pTransformer->Start(m_pDIBSource, &m_ImageMatrix, m_Flags, &clip_box);
674         return TRUE;
675     }
676     if (m_ImageMatrix.a < 0) {
677         dest_width = -dest_width;
678     }
679     if (m_ImageMatrix.d > 0) {
680         dest_height = -dest_height;
681     }
682     int dest_left, dest_top;
683     dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
684     dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
685     if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) {
686         if (m_pRenderStatus->m_pDevice->StretchDIBits(m_pDIBSource, dest_left, dest_top,
687                 dest_width, dest_height, m_Flags, NULL, m_BlendType)) {
688             return FALSE;
689         }
690     }
691     if (m_pDIBSource->IsAlphaMask()) {
692         if (m_BitmapAlpha != 255) {
693             m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
694         }
695         if (m_pRenderStatus->m_pDevice->StretchBitMask(m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_FillArgb, m_Flags)) {
696             return FALSE;
697         }
698     }
699     if (m_pRenderStatus->m_bPrint && !(m_pRenderStatus->m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
700         m_Result = FALSE;
701         return TRUE;
702     }
703     FX_RECT clip_box = m_pRenderStatus->m_pDevice->GetClipBox();
704     FX_RECT dest_rect = clip_box;
705     dest_rect.Intersect(image_rect);
706     FX_RECT dest_clip(dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
707                       dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
708     CFX_DIBitmap* pStretched = m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip);
709     if (pStretched) {
710         m_pRenderStatus->CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top, m_FillArgb,
711                                            m_BitmapAlpha, m_BlendType, FALSE);
712         delete pStretched;
713         pStretched = NULL;
714     }
715     return FALSE;
716 }
717 FX_BOOL CPDF_ImageRenderer::StartBitmapAlpha()
718 {
719     if (m_pDIBSource->IsOpaqueImage()) {
720         CFX_PathData path;
721         path.AppendRect(0, 0, 1, 1);
722         path.Transform(&m_ImageMatrix);
723         FX_DWORD fill_color = ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha);
724         m_pRenderStatus->m_pDevice->DrawPath(&path, NULL, NULL, fill_color, 0, FXFILL_WINDING);
725     } else {
726         const CFX_DIBSource* pAlphaMask = m_pDIBSource->IsAlphaMask() ? m_pDIBSource : m_pDIBSource->GetAlphaMask();
727         if (FXSYS_fabs(m_ImageMatrix.b) >= 0.5f || FXSYS_fabs(m_ImageMatrix.c) >= 0.5f) {
728             int left, top;
729             CFX_DIBitmap* pTransformed = pAlphaMask->TransformTo(&m_ImageMatrix, left, top);
730             if (pTransformed == NULL) {
731                 return TRUE;
732             }
733             m_pRenderStatus->m_pDevice->SetBitMask(pTransformed, left, top, ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
734             delete pTransformed;
735         } else {
736             CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
737             FX_RECT image_rect = image_rect_f.GetOutterRect();
738             int dest_width = m_ImageMatrix.a > 0 ? image_rect.Width() : -image_rect.Width();
739             int dest_height = m_ImageMatrix.d > 0 ? -image_rect.Height() : image_rect.Height();
740             int left = dest_width > 0 ? image_rect.left : image_rect.right;
741             int top = dest_height > 0 ? image_rect.top : image_rect.bottom;
742             m_pRenderStatus->m_pDevice->StretchBitMask(pAlphaMask, left, top, dest_width, dest_height,
743                     ArgbEncode(0xff, m_BitmapAlpha, m_BitmapAlpha, m_BitmapAlpha));
744         }
745         if (m_pDIBSource != pAlphaMask) {
746             delete pAlphaMask;
747         }
748     }
749     return FALSE;
750 }
751 FX_BOOL CPDF_ImageRenderer::Continue(IFX_Pause* pPause)
752 {
753     if (m_Status == 1) {
754         if (m_pQuickStretcher->Continue(pPause)) {
755             return TRUE;
756         }
757         if (m_pQuickStretcher->m_pBitmap->IsAlphaMask())
758             m_pRenderStatus->m_pDevice->SetBitMask(m_pQuickStretcher->m_pBitmap, m_pQuickStretcher->m_ResultLeft,
759                                                    m_pQuickStretcher->m_ResultTop, m_FillArgb);
760         else
761             m_pRenderStatus->m_pDevice->SetDIBits(m_pQuickStretcher->m_pBitmap, m_pQuickStretcher->m_ResultLeft,
762                                                   m_pQuickStretcher->m_ResultTop, m_BlendType);
763         return FALSE;
764     }
765     if (m_Status == 2) {
766         if (m_pTransformer->Continue(pPause)) {
767             return TRUE;
768         }
769         CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach();
770         if (pBitmap == NULL) {
771             return FALSE;
772         }
773         if (pBitmap->IsAlphaMask()) {
774             if (m_BitmapAlpha != 255) {
775                 m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
776             }
777             m_Result = m_pRenderStatus->m_pDevice->SetBitMask(pBitmap,
778                        m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop, m_FillArgb);
779         } else {
780             if (m_BitmapAlpha != 255) {
781                 pBitmap->MultiplyAlpha(m_BitmapAlpha);
782             }
783             m_Result = m_pRenderStatus->m_pDevice->SetDIBits(pBitmap,
784                        m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop, m_BlendType);
785         }
786         delete pBitmap;
787         return FALSE;
788     }
789     if (m_Status == 3) {
790         return m_pRenderStatus->m_pDevice->ContinueDIBits(m_DeviceHandle, pPause);
791     }
792     if (m_Status == 4) {
793         if (m_Loader.Continue(m_LoadHandle, pPause)) {
794             return TRUE;
795         }
796         if (StartRenderDIBSource()) {
797             return Continue(pPause);
798         }
799     }
800     return FALSE;
801 }
802 CPDF_QuickStretcher::CPDF_QuickStretcher()
803 {
804     m_pBitmap = NULL;
805     m_pDecoder = NULL;
806     m_pCS = NULL;
807 }
808 CPDF_QuickStretcher::~CPDF_QuickStretcher()
809 {
810     delete m_pBitmap;
811     if (m_pCS) {
812         m_pCS->ReleaseCS();
813     }
814     delete m_pDecoder;
815 }
816 ICodec_ScanlineDecoder* FPDFAPI_CreateFlateDecoder(const uint8_t* src_buf, FX_DWORD src_size, int width, int height,
817         int nComps, int bpc, const CPDF_Dictionary* pParams);
818 FX_BOOL CPDF_QuickStretcher::Start(CPDF_ImageObject* pImageObj, CFX_AffineMatrix* pImage2Device, const FX_RECT* pClipBox)
819 {
820     if (FXSYS_fabs(pImage2Device->a) < FXSYS_fabs(pImage2Device->b) * 10 && FXSYS_fabs(pImage2Device->d) < FXSYS_fabs(pImage2Device->c) * 10) {
821         return FALSE;
822     }
823     CFX_FloatRect image_rect_f = pImage2Device->GetUnitRect();
824     FX_RECT image_rect = image_rect_f.GetOutterRect();
825     m_DestWidth = image_rect.Width();
826     m_DestHeight = image_rect.Height();
827     m_bFlipX = pImage2Device->a < 0;
828     m_bFlipY = pImage2Device->d > 0;
829     FX_RECT result_rect = *pClipBox;
830     result_rect.Intersect(image_rect);
831     if (result_rect.IsEmpty()) {
832         return FALSE;
833     }
834     m_ResultWidth = result_rect.Width();
835     m_ResultHeight = result_rect.Height();
836     m_ResultLeft = result_rect.left;
837     m_ResultTop = result_rect.top;
838     m_ClipLeft = result_rect.left - image_rect.left;
839     m_ClipTop = result_rect.top - image_rect.top;
840     CPDF_Dictionary* pDict = pImageObj->m_pImage->GetDict();
841     if (pDict->GetInteger(FX_BSTRC("BitsPerComponent")) != 8) {
842         return FALSE;
843     }
844     if (pDict->KeyExist(FX_BSTRC("SMask")) || pDict->KeyExist(FX_BSTRC("Mask"))) {
845         return FALSE;
846     }
847     m_SrcWidth = pDict->GetInteger(FX_BSTRC("Width"));
848     m_SrcHeight = pDict->GetInteger(FX_BSTRC("Height"));
849     m_pCS = NULL;
850     m_Bpp = 3;
851     CPDF_Object* pCSObj = pDict->GetElementValue(FX_BSTRC("ColorSpace"));
852     if (pCSObj == NULL) {
853         return FALSE;
854     }
855     m_pCS = CPDF_ColorSpace::Load(pImageObj->m_pImage->GetDocument(), pCSObj);
856     if (m_pCS == NULL) {
857         return FALSE;
858     }
859     if (!_IsSupported(m_pCS)) {
860         return FALSE;
861     }
862     m_Bpp = m_pCS->CountComponents();
863     if (m_pCS->sRGB()) {
864         m_pCS->ReleaseCS();
865         m_pCS = NULL;
866     }
867     CPDF_Stream* pStream = pImageObj->m_pImage->GetStream();
868     m_StreamAcc.LoadAllData(pStream, FALSE, m_SrcWidth * m_SrcHeight * m_Bpp, TRUE);
869     m_pDecoder = NULL;
870     if (!m_StreamAcc.GetImageDecoder().IsEmpty()) {
871         if (m_StreamAcc.GetImageDecoder() == FX_BSTRC("DCTDecode")) {
872             const CPDF_Dictionary* pParam = m_StreamAcc.GetImageParam();
873             m_pDecoder = CPDF_ModuleMgr::Get()->GetJpegModule()->CreateDecoder(
874                              m_StreamAcc.GetData(), m_StreamAcc.GetSize(), m_SrcWidth, m_SrcHeight, m_Bpp,
875                              pParam ? pParam->GetInteger(FX_BSTRC("ColorTransform"), 1) : 1);
876         } else if (m_StreamAcc.GetImageDecoder() == FX_BSTRC("FlateDecode")) {
877             m_pDecoder = FPDFAPI_CreateFlateDecoder(
878                              m_StreamAcc.GetData(), m_StreamAcc.GetSize(), m_SrcWidth, m_SrcHeight, m_Bpp, 8,
879                              m_StreamAcc.GetImageParam());
880         } else {
881             return FALSE;
882         }
883         m_pDecoder->DownScale(m_DestWidth, m_DestHeight);
884     }
885     m_pBitmap = new CFX_DIBitmap;
886 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
887     m_pBitmap->Create(m_ResultWidth, m_ResultHeight, FXDIB_Rgb32);
888 #else
889     m_pBitmap->Create(m_ResultWidth, m_ResultHeight, FXDIB_Rgb);
890 #endif
891     m_LineIndex = 0;
892     return TRUE;
893 }
894 FX_BOOL CPDF_QuickStretcher::Continue(IFX_Pause* pPause)
895 {
896     uint8_t* result_buf = m_pBitmap->GetBuffer();
897     int src_width = m_pDecoder ? m_pDecoder->GetWidth() : m_SrcWidth;
898     int src_height = m_pDecoder ? m_pDecoder->GetHeight() : m_SrcHeight;
899     int src_pitch = src_width * m_Bpp;
900     while (m_LineIndex < m_ResultHeight) {
901         int dest_y, src_y;
902         if (m_bFlipY) {
903             dest_y = m_ResultHeight - m_LineIndex - 1;
904             src_y = (m_DestHeight - (dest_y + m_ClipTop) - 1) * src_height / m_DestHeight;
905         } else {
906             dest_y = m_LineIndex;
907             src_y = (dest_y + m_ClipTop) * src_height / m_DestHeight;
908         }
909         const uint8_t* src_scan;
910         if (m_pDecoder) {
911             src_scan = m_pDecoder->GetScanline(src_y);
912             if (src_scan == NULL) {
913                 break;
914             }
915         } else {
916             src_scan = m_StreamAcc.GetData();
917             if (src_scan == NULL) {
918                 break;
919             }
920             src_scan += src_y * src_pitch;
921         }
922         uint8_t* result_scan = result_buf + dest_y * m_pBitmap->GetPitch();
923         for (int x = 0; x < m_ResultWidth; x ++) {
924             int dest_x = m_ClipLeft + x;
925             int src_x = (m_bFlipX ? (m_DestWidth - dest_x - 1) : dest_x) * src_width / m_DestWidth;
926             const uint8_t* src_pixel = src_scan + src_x * m_Bpp;
927             if (m_pCS == NULL) {
928                 *result_scan = src_pixel[2];
929                 result_scan ++;
930                 *result_scan = src_pixel[1];
931                 result_scan ++;
932                 *result_scan = src_pixel[0];
933                 result_scan ++;
934 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
935                 result_scan ++;
936 #endif
937             } else {
938                 m_pCS->TranslateImageLine(result_scan, src_pixel, 1, 0, 0);
939 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
940                 result_scan += 4;
941 #else
942                 result_scan += 3;
943 #endif
944             }
945         }
946         m_LineIndex ++;
947         if (pPause && pPause->NeedToPauseNow()) {
948             return TRUE;
949         }
950     }
951     return FALSE;
952 }
953 CFX_DIBitmap* CPDF_RenderStatus::LoadSMask(CPDF_Dictionary* pSMaskDict,
954         FX_RECT* pClipRect, const CFX_AffineMatrix* pMatrix)
955 {
956     if (pSMaskDict == NULL) {
957         return NULL;
958     }
959     CFX_DIBitmap* pMask = NULL;
960     int width = pClipRect->right - pClipRect->left;
961     int height = pClipRect->bottom - pClipRect->top;
962     FX_BOOL bLuminosity = FALSE;
963     bLuminosity = pSMaskDict->GetConstString(FX_BSTRC("S")) != FX_BSTRC("Alpha");
964     CPDF_Stream* pGroup = pSMaskDict->GetStream(FX_BSTRC("G"));
965     if (pGroup == NULL) {
966         return NULL;
967     }
968     CPDF_Function* pFunc = NULL;
969     CPDF_Object* pFuncObj = pSMaskDict->GetElementValue(FX_BSTRC("TR"));
970     if (pFuncObj && (pFuncObj->GetType() == PDFOBJ_DICTIONARY || pFuncObj->GetType() == PDFOBJ_STREAM)) {
971         pFunc = CPDF_Function::Load(pFuncObj);
972     }
973     CFX_AffineMatrix matrix = *pMatrix;
974     matrix.TranslateI(-pClipRect->left, -pClipRect->top);
975     CPDF_Form form(m_pContext->m_pDocument, m_pContext->m_pPageResources, pGroup);
976     form.ParseContent(NULL, NULL, NULL, NULL);
977     CFX_FxgeDevice bitmap_device;
978 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
979     if (!bitmap_device.Create(width, height, bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask)) {
980         return NULL;
981     }
982 #else
983     if (!bitmap_device.Create(width, height, bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask)) {
984         return NULL;
985     }
986 #endif
987     CFX_DIBitmap& bitmap = *bitmap_device.GetBitmap();
988     CPDF_Object* pCSObj = NULL;
989     CPDF_ColorSpace* pCS = NULL;
990     if (bLuminosity) {
991         CPDF_Array* pBC = pSMaskDict->GetArray(FX_BSTRC("BC"));
992         FX_ARGB back_color = 0xff000000;
993         if (pBC) {
994             CPDF_Dictionary* pDict = pGroup->GetDict();
995             if (pDict && pDict->GetDict(FX_BSTRC("Group")))
996                 pCSObj = pDict->GetDict(FX_BSTRC("Group"))->GetElementValue(FX_BSTRC("CS"));
997             else
998                 pCSObj = NULL;
999             pCS = m_pContext->m_pDocument->LoadColorSpace(pCSObj);
1000             if (pCS) {
1001                 FX_FLOAT R, G, B;
1002                 FX_DWORD comps = 8;
1003                 if (pCS->CountComponents() > static_cast<int32_t>(comps)) {
1004                     comps = (FX_DWORD)pCS->CountComponents();
1005                 }
1006                 CFX_FixedBufGrow<FX_FLOAT, 8> float_array(comps);
1007                 FX_FLOAT* pFloats = float_array;
1008                 FX_SAFE_DWORD num_floats = comps;
1009                 num_floats *= sizeof(FX_FLOAT);
1010                 if (!num_floats.IsValid()) {
1011                     return NULL;
1012                 }
1013                 FXSYS_memset(pFloats, 0, num_floats.ValueOrDie());
1014                 int count = pBC->GetCount() > 8 ? 8 : pBC->GetCount();
1015                 for (int i = 0; i < count; i ++) {
1016                     pFloats[i] = pBC->GetNumber(i);
1017                 }
1018                 pCS->GetRGB(pFloats, R, G, B);
1019                 back_color = 0xff000000 | ((int32_t)(R * 255) << 16) | ((int32_t)(G * 255) << 8) | (int32_t)(B * 255);
1020                 m_pContext->m_pDocument->GetPageData()->ReleaseColorSpace(pCSObj);
1021             }
1022         }
1023         bitmap.Clear(back_color);
1024     } else {
1025         bitmap.Clear(0);
1026     }
1027     CPDF_Dictionary* pFormResource = NULL;
1028     if (form.m_pFormDict) {
1029         pFormResource = form.m_pFormDict->GetDict(FX_BSTRC("Resources"));
1030     }
1031     CPDF_RenderOptions options;
1032     options.m_ColorMode = bLuminosity ? RENDER_COLOR_NORMAL : RENDER_COLOR_ALPHA;
1033     CPDF_RenderStatus status;
1034     status.Initialize(m_pContext, &bitmap_device, NULL, NULL, NULL, NULL,
1035                       &options, 0, m_bDropObjects, pFormResource, TRUE, NULL, 0, pCS ? pCS->GetFamily() : 0, bLuminosity);
1036     status.RenderObjectList(&form, &matrix);
1037     pMask = new CFX_DIBitmap;
1038     if (!pMask->Create(width, height, FXDIB_8bppMask)) {
1039         delete pMask;
1040         return NULL;
1041     }
1042     uint8_t* dest_buf = pMask->GetBuffer();
1043     int dest_pitch = pMask->GetPitch();
1044     uint8_t* src_buf = bitmap.GetBuffer();
1045     int src_pitch = bitmap.GetPitch();
1046     uint8_t* pTransfer = FX_Alloc(uint8_t, 256);
1047     if (pFunc) {
1048         CFX_FixedBufGrow<FX_FLOAT, 16> results(pFunc->CountOutputs());
1049         for (int i = 0; i < 256; i ++) {
1050             FX_FLOAT input = (FX_FLOAT)i / 255.0f;
1051             int nresult;
1052             pFunc->Call(&input, 1, results, nresult);
1053             pTransfer[i] = FXSYS_round(results[0] * 255);
1054         }
1055     } else {
1056         for (int i = 0; i < 256; i ++) {
1057             pTransfer[i] = i;
1058         }
1059     }
1060     if (bLuminosity) {
1061         int Bpp = bitmap.GetBPP() / 8;
1062         for (int row = 0; row < height; row ++) {
1063             uint8_t* dest_pos = dest_buf + row * dest_pitch;
1064             uint8_t* src_pos = src_buf + row * src_pitch;
1065             for (int col = 0; col < width; col ++) {
1066                 *dest_pos ++ = pTransfer[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)];
1067                 src_pos += Bpp;
1068             }
1069         }
1070     } else if (pFunc) {
1071         int size = dest_pitch * height;
1072         for (int i = 0; i < size; i ++) {
1073             dest_buf[i] = pTransfer[src_buf[i]];
1074         }
1075     } else {
1076         FXSYS_memcpy(dest_buf, src_buf, dest_pitch * height);
1077     }
1078     delete pFunc;
1079     FX_Free(pTransfer);
1080     return pMask;
1081 }