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