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_page.h"
8#include "../../../include/fpdfapi/fpdf_pageobj.h"
9#include "../../../include/fpdfapi/fpdf_module.h"
10#include "../../../include/fpdfapi/fpdf_render.h"
11#include "pageint.h"
12#include "../fpdf_render/render_int.h"
13void CPDF_GraphicStates::DefaultStates()
14{
15    m_ColorState.New()->Default();
16}
17void CPDF_GraphicStates::CopyStates(const CPDF_GraphicStates& src)
18{
19    m_ClipPath = src.m_ClipPath;
20    m_GraphState = src.m_GraphState;
21    m_ColorState = src.m_ColorState;
22    m_TextState = src.m_TextState;
23    m_GeneralState = src.m_GeneralState;
24}
25CPDF_ClipPathData::CPDF_ClipPathData()
26{
27    m_PathCount = 0;
28    m_pPathList = NULL;
29    m_pTypeList = NULL;
30    m_TextCount = 0;
31    m_pTextList = NULL;
32}
33CPDF_ClipPathData::~CPDF_ClipPathData()
34{
35    int i;
36    delete[] m_pPathList;
37    if (m_pTypeList) {
38        FX_Free(m_pTypeList);
39    }
40    for (i = m_TextCount - 1; i > -1; i --)
41        if (m_pTextList[i]) {
42            delete m_pTextList[i];
43        }
44    if (m_pTextList) {
45        FX_Free(m_pTextList);
46    }
47}
48CPDF_ClipPathData::CPDF_ClipPathData(const CPDF_ClipPathData& src)
49{
50    m_pPathList = NULL;
51    m_pPathList = NULL;
52    m_pTextList = NULL;
53    m_PathCount = src.m_PathCount;
54    if (m_PathCount) {
55        int alloc_size = m_PathCount;
56        if (alloc_size % 8) {
57            alloc_size += 8 - (alloc_size % 8);
58        }
59        m_pPathList = new CPDF_Path[alloc_size];
60        for (int i = 0; i < m_PathCount; i ++) {
61            m_pPathList[i] = src.m_pPathList[i];
62        }
63        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);
64        FXSYS_memcpy32(m_pTypeList, src.m_pTypeList, m_PathCount);
65    } else {
66        m_pPathList = NULL;
67        m_pTypeList = NULL;
68    }
69    m_TextCount = src.m_TextCount;
70    if (m_TextCount) {
71        m_pTextList = FX_Alloc(CPDF_TextObject*, m_TextCount);
72        for (int i = 0; i < m_TextCount; i ++) {
73            if (src.m_pTextList[i]) {
74                m_pTextList[i] = new CPDF_TextObject;
75                m_pTextList[i]->Copy(src.m_pTextList[i]);
76            } else {
77                m_pTextList[i] = NULL;
78            }
79        }
80    } else {
81        m_pTextList = NULL;
82    }
83}
84void CPDF_ClipPathData::SetCount(int path_count, int text_count)
85{
86    ASSERT(m_TextCount == 0 && m_PathCount == 0);
87    if (path_count) {
88        m_PathCount = path_count;
89        int alloc_size = (path_count + 7) / 8 * 8;
90        m_pPathList = new CPDF_Path[alloc_size];
91        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);
92    }
93    if (text_count) {
94        m_TextCount = text_count;
95        m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);
96    }
97}
98CPDF_Rect CPDF_ClipPath::GetClipBox() const
99{
100    CPDF_Rect rect;
101    FX_BOOL bStarted = FALSE;
102    int count = GetPathCount();
103    if (count) {
104        rect = GetPath(0).GetBoundingBox();
105        for (int i = 1; i < count; i ++) {
106            CPDF_Rect path_rect = GetPath(i).GetBoundingBox();
107            rect.Intersect(path_rect);
108        }
109        bStarted = TRUE;
110    }
111    count = GetTextCount();
112    if (count) {
113        CPDF_Rect layer_rect;
114        FX_BOOL bLayerStarted = FALSE;
115        for (int i = 0; i < count; i ++) {
116            CPDF_TextObject* pTextObj = GetText(i);
117            if (pTextObj == NULL) {
118                if (!bStarted) {
119                    rect = layer_rect;
120                    bStarted = TRUE;
121                } else {
122                    rect.Intersect(layer_rect);
123                }
124                bLayerStarted = FALSE;
125            } else {
126                if (!bLayerStarted) {
127                    layer_rect = pTextObj->GetBBox(NULL);
128                    bLayerStarted = TRUE;
129                } else {
130                    layer_rect.Union(pTextObj->GetBBox(NULL));
131                }
132            }
133        }
134    }
135    return rect;
136}
137void CPDF_ClipPath::AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)
138{
139    CPDF_ClipPathData* pData = GetModify();
140    if (pData->m_PathCount && bAutoMerge) {
141        CPDF_Path old_path = pData->m_pPathList[pData->m_PathCount - 1];
142        if (old_path.IsRect()) {
143            CPDF_Rect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),
144                               old_path.GetPointX(2), old_path.GetPointY(2));
145            CPDF_Rect new_rect = path.GetBoundingBox();
146            if (old_rect.Contains(new_rect)) {
147                pData->m_PathCount --;
148                pData->m_pPathList[pData->m_PathCount].SetNull();
149            }
150        }
151    }
152    if (pData->m_PathCount % 8 == 0) {
153        CPDF_Path* pNewPath = new CPDF_Path[pData->m_PathCount + 8];
154        for (int i = 0; i < pData->m_PathCount; i ++) {
155            pNewPath[i] = pData->m_pPathList[i];
156        }
157        delete[] pData->m_pPathList;
158        FX_BYTE* pNewType = FX_Alloc(FX_BYTE, pData->m_PathCount + 8);
159        FXSYS_memcpy32(pNewType, pData->m_pTypeList, pData->m_PathCount);
160        if (pData->m_pTypeList) {
161            FX_Free(pData->m_pTypeList);
162        }
163        pData->m_pPathList = pNewPath;
164        pData->m_pTypeList = pNewType;
165    }
166    pData->m_pPathList[pData->m_PathCount] = path;
167    pData->m_pTypeList[pData->m_PathCount] = (FX_BYTE)type;
168    pData->m_PathCount ++;
169}
170void CPDF_ClipPath::DeletePath(int index)
171{
172    CPDF_ClipPathData* pData = GetModify();
173    if (index >= pData->m_PathCount) {
174        return;
175    }
176    pData->m_pPathList[index].SetNull();
177    for (int i = index; i < pData->m_PathCount - 1; i ++) {
178        pData->m_pPathList[i] = pData->m_pPathList[i + 1];
179    }
180    pData->m_pPathList[pData->m_PathCount - 1].SetNull();
181    FXSYS_memmove32(pData->m_pTypeList + index, pData->m_pTypeList + index + 1, pData->m_PathCount - index - 1);
182    pData->m_PathCount --;
183}
184#define FPDF_CLIPPATH_MAX_TEXTS 1024
185void CPDF_ClipPath::AppendTexts(CPDF_TextObject** pTexts, int count)
186{
187    CPDF_ClipPathData* pData = GetModify();
188    if (pData->m_TextCount + count > FPDF_CLIPPATH_MAX_TEXTS) {
189        for (int i = 0; i < count; i ++) {
190            delete pTexts[i];
191        }
192        return;
193    }
194    CPDF_TextObject** pNewList = FX_Alloc(CPDF_TextObject*, pData->m_TextCount + count + 1);
195    if (pData->m_pTextList) {
196        FXSYS_memcpy32(pNewList, pData->m_pTextList, pData->m_TextCount * sizeof(CPDF_TextObject*));
197        FX_Free(pData->m_pTextList);
198    }
199    pData->m_pTextList = pNewList;
200    for (int i = 0; i < count; i ++) {
201        pData->m_pTextList[pData->m_TextCount + i] = pTexts[i];
202    }
203    pData->m_pTextList[pData->m_TextCount + count] = NULL;
204    pData->m_TextCount += count + 1;
205}
206void CPDF_ClipPath::Transform(const CPDF_Matrix& matrix)
207{
208    CPDF_ClipPathData* pData = GetModify();
209    int i;
210    for (i = 0; i < pData->m_PathCount; i ++) {
211        pData->m_pPathList[i].Transform(&matrix);
212    }
213    for (i = 0; i < pData->m_TextCount; i ++)
214        if (pData->m_pTextList[i]) {
215            pData->m_pTextList[i]->Transform(matrix);
216        }
217}
218CPDF_ColorStateData::CPDF_ColorStateData(const CPDF_ColorStateData& src)
219{
220    m_FillColor.Copy(&src.m_FillColor);
221    m_FillRGB = src.m_FillRGB;
222    m_StrokeColor.Copy(&src.m_StrokeColor);
223    m_StrokeRGB = src.m_StrokeRGB;
224}
225void CPDF_ColorStateData::Default()
226{
227    m_FillRGB = m_StrokeRGB = 0;
228    m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
229    m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
230}
231void CPDF_ColorState::SetFillColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
232{
233    CPDF_ColorStateData* pData = GetModify();
234    SetColor(pData->m_FillColor, pData->m_FillRGB, pCS, pValue, nValues);
235}
236void CPDF_ColorState::SetStrokeColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
237{
238    CPDF_ColorStateData* pData = GetModify();
239    SetColor(pData->m_StrokeColor, pData->m_StrokeRGB, pCS, pValue, nValues);
240}
241void CPDF_ColorState::SetColor(CPDF_Color& color, FX_DWORD& rgb, CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
242{
243    if (pCS) {
244        color.SetColorSpace(pCS);
245    } else if (color.IsNull()) {
246        color.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
247    }
248    if (color.m_pCS->CountComponents() > nValues) {
249        return;
250    }
251    color.SetValue(pValue);
252    int R, G, B;
253    rgb = color.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
254}
255void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
256{
257    CPDF_ColorStateData* pData = GetModify();
258    pData->m_FillColor.SetValue(pPattern, pValue, nValues);
259    int R, G, B;
260    FX_BOOL ret = pData->m_FillColor.GetRGB(R, G, B);
261    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
262        pData->m_FillRGB = 0x00BFBFBF;
263        return;
264    }
265    pData->m_FillRGB = ret ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
266}
267void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
268{
269    CPDF_ColorStateData* pData = GetModify();
270    pData->m_StrokeColor.SetValue(pPattern, pValue, nValues);
271    int R, G, B;
272    FX_BOOL ret = pData->m_StrokeColor.GetRGB(R, G, B);
273    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
274        pData->m_StrokeRGB = 0x00BFBFBF;
275        return;
276    }
277    pData->m_StrokeRGB = pData->m_StrokeColor.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
278}
279CPDF_TextStateData::CPDF_TextStateData()
280{
281    m_pFont = NULL;
282    m_pDocument = NULL;
283    m_FontSize = 1.0f;
284    m_WordSpace = 0;
285    m_CharSpace = 0;
286    m_TextMode = 0;
287    m_Matrix[0] = m_Matrix[3] = 1.0f;
288    m_Matrix[1] = m_Matrix[2] = 0;
289    m_CTM[0] = m_CTM[3] = 1.0f;
290    m_CTM[1] = m_CTM[2] = 0;
291}
292CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src)
293{
294    if (this == &src) {
295        return;
296    }
297    FXSYS_memcpy32(this, &src, sizeof(CPDF_TextStateData));
298    if (m_pDocument && m_pFont) {
299        m_pFont = m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);
300    }
301}
302CPDF_TextStateData::~CPDF_TextStateData()
303{
304    if (m_pDocument && m_pFont) {
305        CPDF_DocPageData *pPageData = m_pDocument->GetPageData();
306        if (pPageData && !pPageData->IsForceClear()) {
307            pPageData->ReleaseFont(m_pFont->GetFontDict());
308        }
309    }
310}
311void CPDF_TextState::SetFont(CPDF_Font* pFont)
312{
313    CPDF_TextStateData* pStateData = GetModify();
314    if (pStateData) {
315        CPDF_Document* pDoc = pStateData->m_pDocument;
316        CPDF_DocPageData *pPageData = pDoc ? pDoc->GetPageData() : NULL;
317        if (pPageData && pStateData->m_pFont && !pPageData->IsForceClear()) {
318            pPageData->ReleaseFont(pStateData->m_pFont->GetFontDict());
319        }
320        pStateData->m_pDocument = pFont ? pFont->m_pDocument : NULL;
321        pStateData->m_pFont = pFont;
322    }
323}
324FX_FLOAT CPDF_TextState::GetFontSizeV() const
325{
326    FX_FLOAT* pMatrix = GetMatrix();
327    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[1], pMatrix[3]);
328    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());
329    return (FX_FLOAT)FXSYS_fabs(size);
330}
331FX_FLOAT CPDF_TextState::GetFontSizeH() const
332{
333    FX_FLOAT* pMatrix = GetMatrix();
334    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[0], pMatrix[2]);
335    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());
336    return (FX_FLOAT)FXSYS_fabs(size);
337}
338FX_FLOAT CPDF_TextState::GetBaselineAngle() const
339{
340    FX_FLOAT* m_Matrix = GetMatrix();
341    return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);
342}
343FX_FLOAT CPDF_TextState::GetShearAngle() const
344{
345    FX_FLOAT* m_Matrix = GetMatrix();
346    FX_FLOAT shear_angle = FXSYS_atan2(m_Matrix[1], m_Matrix[3]);
347    return GetBaselineAngle() + shear_angle;
348}
349CPDF_GeneralStateData::CPDF_GeneralStateData()
350{
351    FXSYS_memset32(this, 0, sizeof(CPDF_GeneralStateData));
352    FXSYS_strcpy((FX_LPSTR)m_BlendMode, "Normal");
353    m_StrokeAlpha = 1.0f;
354    m_FillAlpha = 1.0f;
355    m_Flatness = 1.0f;
356    m_Matrix.SetIdentity();
357}
358CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src)
359{
360    FXSYS_memcpy32(this, &src, sizeof(CPDF_GeneralStateData));
361    if (src.m_pTransferFunc && src.m_pTransferFunc->m_pPDFDoc) {
362        CPDF_DocRenderData* pDocCache = src.m_pTransferFunc->m_pPDFDoc->GetRenderData();
363        if (!pDocCache) {
364            return;
365        }
366        m_pTransferFunc = pDocCache->GetTransferFunc(m_pTR);
367    }
368}
369CPDF_GeneralStateData::~CPDF_GeneralStateData()
370{
371    if (m_pTransferFunc && m_pTransferFunc->m_pPDFDoc) {
372        CPDF_DocRenderData* pDocCache = m_pTransferFunc->m_pPDFDoc->GetRenderData();
373        if (!pDocCache) {
374            return;
375        }
376        pDocCache->ReleaseTransferFunc(m_pTR);
377    }
378}
379static int GetBlendType(FX_BSTR mode)
380{
381    switch (mode.GetID()) {
382        case FXBSTR_ID('N', 'o', 'r', 'm'):
383        case FXBSTR_ID('C', 'o', 'm', 'p'):
384            return FXDIB_BLEND_NORMAL;
385        case FXBSTR_ID('M', 'u', 'l', 't'):
386            return FXDIB_BLEND_MULTIPLY;
387        case FXBSTR_ID('S', 'c', 'r', 'e'):
388            return FXDIB_BLEND_SCREEN;
389        case FXBSTR_ID('O', 'v', 'e', 'r'):
390            return FXDIB_BLEND_OVERLAY;
391        case FXBSTR_ID('D', 'a', 'r', 'k'):
392            return FXDIB_BLEND_DARKEN;
393        case FXBSTR_ID('L', 'i', 'g', 'h'):
394            return FXDIB_BLEND_LIGHTEN;
395        case FXBSTR_ID('C', 'o', 'l', 'o'):
396            if (mode.GetLength() == 10) {
397                return FXDIB_BLEND_COLORDODGE;
398            }
399            if (mode.GetLength() == 9) {
400                return FXDIB_BLEND_COLORBURN;
401            }
402            return FXDIB_BLEND_COLOR;
403        case FXBSTR_ID('H', 'a', 'r', 'd'):
404            return FXDIB_BLEND_HARDLIGHT;
405        case FXBSTR_ID('S', 'o', 'f', 't'):
406            return FXDIB_BLEND_SOFTLIGHT;
407        case FXBSTR_ID('D', 'i', 'f', 'f'):
408            return FXDIB_BLEND_DIFFERENCE;
409        case FXBSTR_ID('E', 'x', 'c', 'l'):
410            return FXDIB_BLEND_EXCLUSION;
411        case FXBSTR_ID('H', 'u', 'e', 0):
412            return FXDIB_BLEND_HUE;
413        case FXBSTR_ID('S', 'a', 't', 'u'):
414            return FXDIB_BLEND_SATURATION;
415        case FXBSTR_ID('L', 'u', 'm', 'i'):
416            return FXDIB_BLEND_LUMINOSITY;
417    }
418    return FXDIB_BLEND_NORMAL;
419}
420void CPDF_GeneralStateData::SetBlendMode(FX_BSTR blend_mode)
421{
422    if (blend_mode.GetLength() > 15) {
423        return;
424    }
425    FXSYS_memcpy32(m_BlendMode, blend_mode.GetPtr(), blend_mode.GetLength());
426    m_BlendMode[blend_mode.GetLength()] = 0;
427    m_BlendType = ::GetBlendType(blend_mode);
428}
429int RI_StringToId(const CFX_ByteString& ri)
430{
431    FX_DWORD id = ri.GetID();
432    if (id == FXBSTR_ID('A', 'b', 's', 'o')) {
433        return 1;
434    }
435    if (id == FXBSTR_ID('S', 'a', 't', 'u')) {
436        return 2;
437    }
438    if (id == FXBSTR_ID('P', 'e', 'r', 'c')) {
439        return 3;
440    }
441    return 0;
442}
443void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri)
444{
445    GetModify()->m_RenderIntent = RI_StringToId(ri);
446}
447CPDF_AllStates::CPDF_AllStates()
448{
449    m_TextX = m_TextY = m_TextLineX = m_TextLineY = 0;
450    m_TextLeading = 0;
451    m_TextRise = 0;
452    m_TextHorzScale = 1.0f;
453}
454CPDF_AllStates::~CPDF_AllStates()
455{
456}
457void CPDF_AllStates::Copy(const CPDF_AllStates& src)
458{
459    CopyStates(src);
460    m_TextMatrix.Copy(src.m_TextMatrix);
461    m_ParentMatrix.Copy(src.m_ParentMatrix);
462    m_CTM.Copy(src.m_CTM);
463    m_TextX = src.m_TextX;
464    m_TextY = src.m_TextY;
465    m_TextLineX = src.m_TextLineX;
466    m_TextLineY = src.m_TextLineY;
467    m_TextLeading = src.m_TextLeading;
468    m_TextRise = src.m_TextRise;
469    m_TextHorzScale = src.m_TextHorzScale;
470}
471void CPDF_AllStates::SetLineDash(CPDF_Array* pArray, FX_FLOAT phase, FX_FLOAT scale)
472{
473    CFX_GraphStateData* pData = m_GraphState.GetModify();
474    pData->m_DashPhase = FXSYS_Mul(phase, scale);
475    pData->SetDashCount(pArray->GetCount());
476    for (FX_DWORD i = 0; i < pArray->GetCount(); i ++) {
477        pData->m_DashArray[i] = FXSYS_Mul(pArray->GetNumber(i), scale);
478    }
479}
480void CPDF_AllStates::ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser)
481{
482    CPDF_GeneralStateData* pGeneralState = m_GeneralState.GetModify();
483    FX_POSITION pos = pGS->GetStartPos();
484    while (pos) {
485        CFX_ByteString key_str;
486        CPDF_Object* pElement = pGS->GetNextElement(pos, key_str);
487        CPDF_Object* pObject = pElement ? pElement->GetDirect() : NULL;
488        if (pObject == NULL) {
489            continue;
490        }
491        FX_DWORD key = key_str.GetID();
492        switch (key) {
493            case FXBSTR_ID('L', 'W', 0, 0):
494                m_GraphState.GetModify()->m_LineWidth = pObject->GetNumber();
495                break;
496            case FXBSTR_ID('L', 'C', 0, 0):
497                m_GraphState.GetModify()->m_LineCap = (CFX_GraphStateData::LineCap)pObject->GetInteger();
498                break;
499            case FXBSTR_ID('L', 'J', 0, 0):
500                m_GraphState.GetModify()->m_LineJoin = (CFX_GraphStateData::LineJoin)pObject->GetInteger();
501                break;
502            case FXBSTR_ID('M', 'L', 0, 0):
503                m_GraphState.GetModify()->m_MiterLimit = pObject->GetNumber();
504                break;
505            case FXBSTR_ID('D', 0, 0, 0):	{
506                    if (pObject->GetType() != PDFOBJ_ARRAY) {
507                        break;
508                    }
509                    CPDF_Array* pDash = (CPDF_Array*)pObject;
510                    CPDF_Array* pArray = pDash->GetArray(0);
511                    if (pArray == NULL) {
512                        break;
513                    }
514                    SetLineDash(pArray, pDash->GetNumber(1), 1.0f);
515                    break;
516                }
517            case FXBSTR_ID('R', 'I', 0, 0):
518                m_GeneralState.SetRenderIntent(pObject->GetString());
519                break;
520            case FXBSTR_ID('F', 'o', 'n', 't'):	{
521                    if (pObject->GetType() != PDFOBJ_ARRAY) {
522                        break;
523                    }
524                    CPDF_Array* pFont = (CPDF_Array*)pObject;
525                    m_TextState.GetModify()->m_FontSize = pFont->GetNumber(1);
526                    m_TextState.SetFont(pParser->FindFont(pFont->GetString(0)));
527                    break;
528                }
529            case FXBSTR_ID('T', 'R', 0, 0):
530                if (pGS->KeyExist(FX_BSTRC("TR2"))) {
531                    continue;
532                }
533            case FXBSTR_ID('T', 'R', '2', 0):
534                if (pObject && pObject->GetType() != PDFOBJ_NAME) {
535                    pGeneralState->m_pTR = pObject;
536                } else {
537                    pGeneralState->m_pTR = NULL;
538                }
539                break;
540            case FXBSTR_ID('B', 'M', 0, 0):	{
541                    CFX_ByteString mode;
542                    if (pObject->GetType() == PDFOBJ_ARRAY) {
543                        mode = ((CPDF_Array*)pObject)->GetString(0);
544                    } else {
545                        mode = pObject->GetString();
546                    }
547                    pGeneralState->SetBlendMode(mode);
548                    if (pGeneralState->m_BlendType > FXDIB_BLEND_MULTIPLY) {
549                        pParser->m_pObjectList->m_bBackgroundAlphaNeeded = TRUE;
550                    }
551                    break;
552                }
553            case FXBSTR_ID('S', 'M', 'a', 's'):
554                if (pObject && pObject->GetType() == PDFOBJ_DICTIONARY) {
555                    pGeneralState->m_pSoftMask = pObject;
556                    FXSYS_memcpy32(pGeneralState->m_SMaskMatrix, &pParser->m_pCurStates->m_CTM, sizeof(CPDF_Matrix));
557                } else {
558                    pGeneralState->m_pSoftMask = NULL;
559                }
560                break;
561            case FXBSTR_ID('C', 'A', 0, 0):
562                pGeneralState->m_StrokeAlpha = PDF_ClipFloat(pObject->GetNumber());
563                break;
564            case FXBSTR_ID('c', 'a', 0, 0):
565                pGeneralState->m_FillAlpha = PDF_ClipFloat(pObject->GetNumber());
566                break;
567            case FXBSTR_ID('O', 'P', 0, 0):
568                pGeneralState->m_StrokeOP = pObject->GetInteger();
569                if (!pGS->KeyExist(FX_BSTRC("op"))) {
570                    pGeneralState->m_FillOP = pObject->GetInteger();
571                }
572                break;
573            case FXBSTR_ID('o', 'p', 0, 0):
574                pGeneralState->m_FillOP = pObject->GetInteger();
575                break;
576            case FXBSTR_ID('O', 'P', 'M', 0):
577                pGeneralState->m_OPMode = pObject->GetInteger();
578                break;
579            case FXBSTR_ID('B', 'G', 0, 0):
580                if (pGS->KeyExist(FX_BSTRC("BG2"))) {
581                    continue;
582                }
583            case FXBSTR_ID('B', 'G', '2', 0):
584                pGeneralState->m_pBG = pObject;
585                break;
586            case FXBSTR_ID('U', 'C', 'R', 0):
587                if (pGS->KeyExist(FX_BSTRC("UCR2"))) {
588                    continue;
589                }
590            case FXBSTR_ID('U', 'C', 'R', '2'):
591                pGeneralState->m_pUCR = pObject;
592                break;
593            case FXBSTR_ID('H', 'T', 0, 0):
594                pGeneralState->m_pHT = pObject;
595                break;
596            case FXBSTR_ID('F', 'L', 0, 0):
597                pGeneralState->m_Flatness = pObject->GetNumber();
598                break;
599            case FXBSTR_ID('S', 'M', 0, 0):
600                pGeneralState->m_Smoothness = pObject->GetNumber();
601                break;
602            case FXBSTR_ID('S', 'A', 0, 0):
603                pGeneralState->m_StrokeAdjust = pObject->GetInteger();
604                break;
605            case FXBSTR_ID('A', 'I', 'S', 0):
606                pGeneralState->m_AlphaSource = pObject->GetInteger();
607                break;
608            case FXBSTR_ID('T', 'K', 0, 0):
609                pGeneralState->m_TextKnockout = pObject->GetInteger();
610                break;
611        }
612    }
613    pGeneralState->m_Matrix = m_CTM;
614}
615CPDF_ContentMarkItem::CPDF_ContentMarkItem()
616{
617    m_ParamType = None;
618}
619CPDF_ContentMarkItem::CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src)
620{
621    m_MarkName = src.m_MarkName;
622    m_ParamType = src.m_ParamType;
623    if (m_ParamType == DirectDict) {
624        m_pParam = ((CPDF_Dictionary*)src.m_pParam)->Clone();
625    } else {
626        m_pParam = src.m_pParam;
627    }
628}
629CPDF_ContentMarkItem::~CPDF_ContentMarkItem()
630{
631    if (m_ParamType == DirectDict && m_pParam) {
632        ((CPDF_Dictionary*)m_pParam)->Release();
633    }
634}
635FX_BOOL	CPDF_ContentMarkItem::HasMCID() const
636{
637    if (m_pParam && (m_ParamType == DirectDict || m_ParamType == PropertiesDict)) {
638        return ((CPDF_Dictionary *)m_pParam)->KeyExist(FX_BSTRC("MCID"));
639    }
640    return FALSE;
641}
642CPDF_ContentMarkData::CPDF_ContentMarkData(const CPDF_ContentMarkData& src)
643{
644    for (int i = 0; i < src.m_Marks.GetSize(); i ++) {
645        m_Marks.Add(src.m_Marks[i]);
646    }
647}
648int CPDF_ContentMarkData::GetMCID() const
649{
650    CPDF_ContentMarkItem::ParamType type = CPDF_ContentMarkItem::None;
651    for (int i = 0; i < m_Marks.GetSize(); i ++) {
652        type = m_Marks[i].GetParamType();
653        if (type == CPDF_ContentMarkItem::PropertiesDict || type == CPDF_ContentMarkItem::DirectDict) {
654            CPDF_Dictionary *pDict = (CPDF_Dictionary *)m_Marks[i].GetParam();
655            if (pDict->KeyExist(FX_BSTRC("MCID"))) {
656                return pDict->GetInteger(FX_BSTRC("MCID"));
657            }
658        }
659    }
660    return -1;
661}
662void CPDF_ContentMarkData::AddMark(const CFX_ByteString& name, CPDF_Dictionary* pDict, FX_BOOL bDirect)
663{
664    CPDF_ContentMarkItem& item = m_Marks.Add();
665    item.SetName(name);
666    if (pDict == NULL) {
667        return;
668    }
669    item.SetParam(bDirect ? CPDF_ContentMarkItem::DirectDict : CPDF_ContentMarkItem::PropertiesDict,
670                  bDirect ? pDict->Clone() : pDict);
671}
672void CPDF_ContentMarkData::DeleteLastMark()
673{
674    int size = m_Marks.GetSize();
675    if (size == 0) {
676        return;
677    }
678    m_Marks.RemoveAt(size - 1);
679}
680FX_BOOL CPDF_ContentMark::HasMark(FX_BSTR mark) const
681{
682    if (m_pObject == NULL) {
683        return FALSE;
684    }
685    for (int i = 0; i < m_pObject->CountItems(); i ++) {
686        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
687        if (item.GetName() == mark) {
688            return TRUE;
689        }
690    }
691    return FALSE;
692}
693FX_BOOL CPDF_ContentMark::LookupMark(FX_BSTR mark, CPDF_Dictionary*& pDict) const
694{
695    if (m_pObject == NULL) {
696        return FALSE;
697    }
698    for (int i = 0; i < m_pObject->CountItems(); i ++) {
699        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
700        if (item.GetName() == mark) {
701            pDict = NULL;
702            if (item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict ||
703                    item.GetParamType() == CPDF_ContentMarkItem::DirectDict) {
704                pDict = (CPDF_Dictionary*)item.GetParam();
705            }
706            return TRUE;
707        }
708    }
709    return FALSE;
710}
711