70d0743f58b5678fe87f632f712644d5b52ae4ed
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_graph_state.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_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"
13 void CPDF_GraphicStates::DefaultStates()
14 {
15     m_ColorState.New()->Default();
16 }
17 void 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 }
25 CPDF_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 }
33 CPDF_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         delete m_pTextList[i];
42     if (m_pTextList) {
43         FX_Free(m_pTextList);
44     }
45 }
46 CPDF_ClipPathData::CPDF_ClipPathData(const CPDF_ClipPathData& src)
47 {
48     m_pPathList = NULL;
49     m_pPathList = NULL;
50     m_pTextList = NULL;
51     m_PathCount = src.m_PathCount;
52     if (m_PathCount) {
53         int alloc_size = m_PathCount;
54         if (alloc_size % 8) {
55             alloc_size += 8 - (alloc_size % 8);
56         }
57         m_pPathList = new CPDF_Path[alloc_size];
58         for (int i = 0; i < m_PathCount; i ++) {
59             m_pPathList[i] = src.m_pPathList[i];
60         }
61         m_pTypeList = FX_Alloc(uint8_t, alloc_size);
62         FXSYS_memcpy(m_pTypeList, src.m_pTypeList, m_PathCount);
63     } else {
64         m_pPathList = NULL;
65         m_pTypeList = NULL;
66     }
67     m_TextCount = src.m_TextCount;
68     if (m_TextCount) {
69         m_pTextList = FX_Alloc(CPDF_TextObject*, m_TextCount);
70         for (int i = 0; i < m_TextCount; i ++) {
71             if (src.m_pTextList[i]) {
72                 m_pTextList[i] = new CPDF_TextObject;
73                 m_pTextList[i]->Copy(src.m_pTextList[i]);
74             } else {
75                 m_pTextList[i] = NULL;
76             }
77         }
78     } else {
79         m_pTextList = NULL;
80     }
81 }
82 void CPDF_ClipPathData::SetCount(int path_count, int text_count)
83 {
84     ASSERT(m_TextCount == 0 && m_PathCount == 0);
85     if (path_count) {
86         m_PathCount = path_count;
87         int alloc_size = (path_count + 7) / 8 * 8;
88         m_pPathList = new CPDF_Path[alloc_size];
89         m_pTypeList = FX_Alloc(uint8_t, alloc_size);
90     }
91     if (text_count) {
92         m_TextCount = text_count;
93         m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);
94     }
95 }
96 CPDF_Rect CPDF_ClipPath::GetClipBox() const
97 {
98     CPDF_Rect rect;
99     FX_BOOL bStarted = FALSE;
100     int count = GetPathCount();
101     if (count) {
102         rect = GetPath(0).GetBoundingBox();
103         for (int i = 1; i < count; i ++) {
104             CPDF_Rect path_rect = GetPath(i).GetBoundingBox();
105             rect.Intersect(path_rect);
106         }
107         bStarted = TRUE;
108     }
109     count = GetTextCount();
110     if (count) {
111         CPDF_Rect layer_rect;
112         FX_BOOL bLayerStarted = FALSE;
113         for (int i = 0; i < count; i ++) {
114             CPDF_TextObject* pTextObj = GetText(i);
115             if (pTextObj == NULL) {
116                 if (!bStarted) {
117                     rect = layer_rect;
118                     bStarted = TRUE;
119                 } else {
120                     rect.Intersect(layer_rect);
121                 }
122                 bLayerStarted = FALSE;
123             } else {
124                 if (!bLayerStarted) {
125                     layer_rect = pTextObj->GetBBox(NULL);
126                     bLayerStarted = TRUE;
127                 } else {
128                     layer_rect.Union(pTextObj->GetBBox(NULL));
129                 }
130             }
131         }
132     }
133     return rect;
134 }
135 void CPDF_ClipPath::AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)
136 {
137     CPDF_ClipPathData* pData = GetModify();
138     if (pData->m_PathCount && bAutoMerge) {
139         CPDF_Path old_path = pData->m_pPathList[pData->m_PathCount - 1];
140         if (old_path.IsRect()) {
141             CPDF_Rect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),
142                                old_path.GetPointX(2), old_path.GetPointY(2));
143             CPDF_Rect new_rect = path.GetBoundingBox();
144             if (old_rect.Contains(new_rect)) {
145                 pData->m_PathCount --;
146                 pData->m_pPathList[pData->m_PathCount].SetNull();
147             }
148         }
149     }
150     if (pData->m_PathCount % 8 == 0) {
151         CPDF_Path* pNewPath = new CPDF_Path[pData->m_PathCount + 8];
152         for (int i = 0; i < pData->m_PathCount; i ++) {
153             pNewPath[i] = pData->m_pPathList[i];
154         }
155         delete[] pData->m_pPathList;
156         uint8_t* pNewType = FX_Alloc(uint8_t, pData->m_PathCount + 8);
157         FXSYS_memcpy(pNewType, pData->m_pTypeList, pData->m_PathCount);
158         if (pData->m_pTypeList) {
159             FX_Free(pData->m_pTypeList);
160         }
161         pData->m_pPathList = pNewPath;
162         pData->m_pTypeList = pNewType;
163     }
164     pData->m_pPathList[pData->m_PathCount] = path;
165     pData->m_pTypeList[pData->m_PathCount] = (uint8_t)type;
166     pData->m_PathCount ++;
167 }
168 void CPDF_ClipPath::DeletePath(int index)
169 {
170     CPDF_ClipPathData* pData = GetModify();
171     if (index >= pData->m_PathCount) {
172         return;
173     }
174     pData->m_pPathList[index].SetNull();
175     for (int i = index; i < pData->m_PathCount - 1; i ++) {
176         pData->m_pPathList[i] = pData->m_pPathList[i + 1];
177     }
178     pData->m_pPathList[pData->m_PathCount - 1].SetNull();
179     FXSYS_memmove(pData->m_pTypeList + index, pData->m_pTypeList + index + 1, pData->m_PathCount - index - 1);
180     pData->m_PathCount --;
181 }
182 #define FPDF_CLIPPATH_MAX_TEXTS 1024
183 void CPDF_ClipPath::AppendTexts(CPDF_TextObject** pTexts, int count)
184 {
185     CPDF_ClipPathData* pData = GetModify();
186     if (pData->m_TextCount + count > FPDF_CLIPPATH_MAX_TEXTS) {
187         for (int i = 0; i < count; i ++) {
188             delete pTexts[i];
189         }
190         return;
191     }
192     CPDF_TextObject** pNewList = FX_Alloc(CPDF_TextObject*, pData->m_TextCount + count + 1);
193     if (pData->m_pTextList) {
194         FXSYS_memcpy(pNewList, pData->m_pTextList, pData->m_TextCount * sizeof(CPDF_TextObject*));
195         FX_Free(pData->m_pTextList);
196     }
197     pData->m_pTextList = pNewList;
198     for (int i = 0; i < count; i ++) {
199         pData->m_pTextList[pData->m_TextCount + i] = pTexts[i];
200     }
201     pData->m_pTextList[pData->m_TextCount + count] = NULL;
202     pData->m_TextCount += count + 1;
203 }
204 void CPDF_ClipPath::Transform(const CPDF_Matrix& matrix)
205 {
206     CPDF_ClipPathData* pData = GetModify();
207     int i;
208     for (i = 0; i < pData->m_PathCount; i ++) {
209         pData->m_pPathList[i].Transform(&matrix);
210     }
211     for (i = 0; i < pData->m_TextCount; i ++)
212         if (pData->m_pTextList[i]) {
213             pData->m_pTextList[i]->Transform(matrix);
214         }
215 }
216 CPDF_ColorStateData::CPDF_ColorStateData(const CPDF_ColorStateData& src)
217 {
218     m_FillColor.Copy(&src.m_FillColor);
219     m_FillRGB = src.m_FillRGB;
220     m_StrokeColor.Copy(&src.m_StrokeColor);
221     m_StrokeRGB = src.m_StrokeRGB;
222 }
223 void CPDF_ColorStateData::Default()
224 {
225     m_FillRGB = m_StrokeRGB = 0;
226     m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
227     m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
228 }
229 void CPDF_ColorState::SetFillColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
230 {
231     CPDF_ColorStateData* pData = GetModify();
232     SetColor(pData->m_FillColor, pData->m_FillRGB, pCS, pValue, nValues);
233 }
234 void CPDF_ColorState::SetStrokeColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
235 {
236     CPDF_ColorStateData* pData = GetModify();
237     SetColor(pData->m_StrokeColor, pData->m_StrokeRGB, pCS, pValue, nValues);
238 }
239 void CPDF_ColorState::SetColor(CPDF_Color& color, FX_DWORD& rgb, CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
240 {
241     if (pCS) {
242         color.SetColorSpace(pCS);
243     } else if (color.IsNull()) {
244         color.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
245     }
246     if (color.m_pCS->CountComponents() > nValues) {
247         return;
248     }
249     color.SetValue(pValue);
250     int R, G, B;
251     rgb = color.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
252 }
253 void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
254 {
255     CPDF_ColorStateData* pData = GetModify();
256     pData->m_FillColor.SetValue(pPattern, pValue, nValues);
257     int R, G, B;
258     FX_BOOL ret = pData->m_FillColor.GetRGB(R, G, B);
259     if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
260         pData->m_FillRGB = 0x00BFBFBF;
261         return;
262     }
263     pData->m_FillRGB = ret ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
264 }
265 void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
266 {
267     CPDF_ColorStateData* pData = GetModify();
268     pData->m_StrokeColor.SetValue(pPattern, pValue, nValues);
269     int R, G, B;
270     FX_BOOL ret = pData->m_StrokeColor.GetRGB(R, G, B);
271     if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
272         pData->m_StrokeRGB = 0x00BFBFBF;
273         return;
274     }
275     pData->m_StrokeRGB = pData->m_StrokeColor.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
276 }
277 CPDF_TextStateData::CPDF_TextStateData()
278 {
279     m_pFont = NULL;
280     m_pDocument = NULL;
281     m_FontSize = 1.0f;
282     m_WordSpace = 0;
283     m_CharSpace = 0;
284     m_TextMode = 0;
285     m_Matrix[0] = m_Matrix[3] = 1.0f;
286     m_Matrix[1] = m_Matrix[2] = 0;
287     m_CTM[0] = m_CTM[3] = 1.0f;
288     m_CTM[1] = m_CTM[2] = 0;
289 }
290 CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src)
291 {
292     if (this == &src) {
293         return;
294     }
295     FXSYS_memcpy(this, &src, sizeof(CPDF_TextStateData));
296     if (m_pDocument && m_pFont) {
297         m_pFont = m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);
298     }
299 }
300 CPDF_TextStateData::~CPDF_TextStateData()
301 {
302     if (m_pDocument && m_pFont) {
303         CPDF_DocPageData *pPageData = m_pDocument->GetPageData();
304         if (pPageData && !pPageData->IsForceClear()) {
305             pPageData->ReleaseFont(m_pFont->GetFontDict());
306         }
307     }
308 }
309 void CPDF_TextState::SetFont(CPDF_Font* pFont)
310 {
311     CPDF_TextStateData* pStateData = GetModify();
312     if (pStateData) {
313         CPDF_Document* pDoc = pStateData->m_pDocument;
314         CPDF_DocPageData *pPageData = pDoc ? pDoc->GetPageData() : NULL;
315         if (pPageData && pStateData->m_pFont && !pPageData->IsForceClear()) {
316             pPageData->ReleaseFont(pStateData->m_pFont->GetFontDict());
317         }
318         pStateData->m_pDocument = pFont ? pFont->m_pDocument : NULL;
319         pStateData->m_pFont = pFont;
320     }
321 }
322 FX_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 }
329 FX_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 }
336 FX_FLOAT CPDF_TextState::GetBaselineAngle() const
337 {
338     FX_FLOAT* m_Matrix = GetMatrix();
339     return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);
340 }
341 FX_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 }
347 CPDF_GeneralStateData::CPDF_GeneralStateData()
348 {
349     FXSYS_memset(this, 0, sizeof(CPDF_GeneralStateData));
350     FXSYS_strcpy((FX_CHAR*)m_BlendMode, "Normal");
351     m_StrokeAlpha = 1.0f;
352     m_FillAlpha = 1.0f;
353     m_Flatness = 1.0f;
354     m_Matrix.SetIdentity();
355 }
356 CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src)
357 {
358     FXSYS_memcpy(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 }
367 CPDF_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 }
377 static int GetBlendType(const CFX_ByteStringC& 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 }
418 void CPDF_GeneralStateData::SetBlendMode(const CFX_ByteStringC& blend_mode)
419 {
420     if (blend_mode.GetLength() > 15) {
421         return;
422     }
423     FXSYS_memcpy(m_BlendMode, blend_mode.GetPtr(), blend_mode.GetLength());
424     m_BlendMode[blend_mode.GetLength()] = 0;
425     m_BlendType = ::GetBlendType(blend_mode);
426 }
427 int 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 }
441 void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri)
442 {
443     GetModify()->m_RenderIntent = RI_StringToId(ri);
444 }
445 CPDF_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 }
452 CPDF_AllStates::~CPDF_AllStates()
453 {
454 }
455 void 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 }
469 void 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 }
478 void 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* pElement = pGS->GetNextElement(pos, key_str);
485         CPDF_Object* pObject = pElement ? pElement->GetDirect() : NULL;
486         if (pObject == NULL) {
487             continue;
488         }
489         FX_DWORD key = key_str.GetID();
490         switch (key) {
491             case FXBSTR_ID('L', 'W', 0, 0):
492                 m_GraphState.GetModify()->m_LineWidth = pObject->GetNumber();
493                 break;
494             case FXBSTR_ID('L', 'C', 0, 0):
495                 m_GraphState.GetModify()->m_LineCap = (CFX_GraphStateData::LineCap)pObject->GetInteger();
496                 break;
497             case FXBSTR_ID('L', 'J', 0, 0):
498                 m_GraphState.GetModify()->m_LineJoin = (CFX_GraphStateData::LineJoin)pObject->GetInteger();
499                 break;
500             case FXBSTR_ID('M', 'L', 0, 0):
501                 m_GraphState.GetModify()->m_MiterLimit = pObject->GetNumber();
502                 break;
503             case FXBSTR_ID('D', 0, 0, 0):       {
504                     if (pObject->GetType() != PDFOBJ_ARRAY) {
505                         break;
506                     }
507                     CPDF_Array* pDash = (CPDF_Array*)pObject;
508                     CPDF_Array* pArray = pDash->GetArray(0);
509                     if (pArray == NULL) {
510                         break;
511                     }
512                     SetLineDash(pArray, pDash->GetNumber(1), 1.0f);
513                     break;
514                 }
515             case FXBSTR_ID('R', 'I', 0, 0):
516                 m_GeneralState.SetRenderIntent(pObject->GetString());
517                 break;
518             case FXBSTR_ID('F', 'o', 'n', 't'): {
519                     if (pObject->GetType() != PDFOBJ_ARRAY) {
520                         break;
521                     }
522                     CPDF_Array* pFont = (CPDF_Array*)pObject;
523                     m_TextState.GetModify()->m_FontSize = pFont->GetNumber(1);
524                     m_TextState.SetFont(pParser->FindFont(pFont->GetString(0)));
525                     break;
526                 }
527             case FXBSTR_ID('T', 'R', 0, 0):
528                 if (pGS->KeyExist(FX_BSTRC("TR2"))) {
529                     continue;
530                 }
531             case FXBSTR_ID('T', 'R', '2', 0):
532                 if (pObject && pObject->GetType() != PDFOBJ_NAME) {
533                     pGeneralState->m_pTR = pObject;
534                 } else {
535                     pGeneralState->m_pTR = NULL;
536                 }
537                 break;
538             case FXBSTR_ID('B', 'M', 0, 0):     {
539                     CFX_ByteString mode;
540                     if (pObject->GetType() == PDFOBJ_ARRAY) {
541                         mode = ((CPDF_Array*)pObject)->GetString(0);
542                     } else {
543                         mode = pObject->GetString();
544                     }
545                     pGeneralState->SetBlendMode(mode);
546                     if (pGeneralState->m_BlendType > FXDIB_BLEND_MULTIPLY) {
547                         pParser->m_pObjectList->m_bBackgroundAlphaNeeded = TRUE;
548                     }
549                     break;
550                 }
551             case FXBSTR_ID('S', 'M', 'a', 's'):
552                 if (pObject && pObject->GetType() == PDFOBJ_DICTIONARY) {
553                     pGeneralState->m_pSoftMask = pObject;
554                     FXSYS_memcpy(pGeneralState->m_SMaskMatrix, &pParser->m_pCurStates->m_CTM, sizeof(CPDF_Matrix));
555                 } else {
556                     pGeneralState->m_pSoftMask = NULL;
557                 }
558                 break;
559             case FXBSTR_ID('C', 'A', 0, 0):
560                 pGeneralState->m_StrokeAlpha = PDF_ClipFloat(pObject->GetNumber());
561                 break;
562             case FXBSTR_ID('c', 'a', 0, 0):
563                 pGeneralState->m_FillAlpha = PDF_ClipFloat(pObject->GetNumber());
564                 break;
565             case FXBSTR_ID('O', 'P', 0, 0):
566                 pGeneralState->m_StrokeOP = pObject->GetInteger();
567                 if (!pGS->KeyExist(FX_BSTRC("op"))) {
568                     pGeneralState->m_FillOP = pObject->GetInteger();
569                 }
570                 break;
571             case FXBSTR_ID('o', 'p', 0, 0):
572                 pGeneralState->m_FillOP = pObject->GetInteger();
573                 break;
574             case FXBSTR_ID('O', 'P', 'M', 0):
575                 pGeneralState->m_OPMode = pObject->GetInteger();
576                 break;
577             case FXBSTR_ID('B', 'G', 0, 0):
578                 if (pGS->KeyExist(FX_BSTRC("BG2"))) {
579                     continue;
580                 }
581             case FXBSTR_ID('B', 'G', '2', 0):
582                 pGeneralState->m_pBG = pObject;
583                 break;
584             case FXBSTR_ID('U', 'C', 'R', 0):
585                 if (pGS->KeyExist(FX_BSTRC("UCR2"))) {
586                     continue;
587                 }
588             case FXBSTR_ID('U', 'C', 'R', '2'):
589                 pGeneralState->m_pUCR = pObject;
590                 break;
591             case FXBSTR_ID('H', 'T', 0, 0):
592                 pGeneralState->m_pHT = pObject;
593                 break;
594             case FXBSTR_ID('F', 'L', 0, 0):
595                 pGeneralState->m_Flatness = pObject->GetNumber();
596                 break;
597             case FXBSTR_ID('S', 'M', 0, 0):
598                 pGeneralState->m_Smoothness = pObject->GetNumber();
599                 break;
600             case FXBSTR_ID('S', 'A', 0, 0):
601                 pGeneralState->m_StrokeAdjust = pObject->GetInteger();
602                 break;
603             case FXBSTR_ID('A', 'I', 'S', 0):
604                 pGeneralState->m_AlphaSource = pObject->GetInteger();
605                 break;
606             case FXBSTR_ID('T', 'K', 0, 0):
607                 pGeneralState->m_TextKnockout = pObject->GetInteger();
608                 break;
609         }
610     }
611     pGeneralState->m_Matrix = m_CTM;
612 }
613 CPDF_ContentMarkItem::CPDF_ContentMarkItem()
614 {
615     m_ParamType = None;
616 }
617 CPDF_ContentMarkItem::CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src)
618 {
619     m_MarkName = src.m_MarkName;
620     m_ParamType = src.m_ParamType;
621     if (m_ParamType == DirectDict) {
622         m_pParam = ((CPDF_Dictionary*)src.m_pParam)->Clone();
623     } else {
624         m_pParam = src.m_pParam;
625     }
626 }
627 CPDF_ContentMarkItem::~CPDF_ContentMarkItem()
628 {
629     if (m_ParamType == DirectDict && m_pParam) {
630         ((CPDF_Dictionary*)m_pParam)->Release();
631     }
632 }
633 FX_BOOL CPDF_ContentMarkItem::HasMCID() const
634 {
635     if (m_pParam && (m_ParamType == DirectDict || m_ParamType == PropertiesDict)) {
636         return ((CPDF_Dictionary *)m_pParam)->KeyExist(FX_BSTRC("MCID"));
637     }
638     return FALSE;
639 }
640 CPDF_ContentMarkData::CPDF_ContentMarkData(const CPDF_ContentMarkData& src)
641 {
642     for (int i = 0; i < src.m_Marks.GetSize(); i ++) {
643         m_Marks.Add(src.m_Marks[i]);
644     }
645 }
646 int CPDF_ContentMarkData::GetMCID() const
647 {
648     CPDF_ContentMarkItem::ParamType type = CPDF_ContentMarkItem::None;
649     for (int i = 0; i < m_Marks.GetSize(); i ++) {
650         type = m_Marks[i].GetParamType();
651         if (type == CPDF_ContentMarkItem::PropertiesDict || type == CPDF_ContentMarkItem::DirectDict) {
652             CPDF_Dictionary *pDict = (CPDF_Dictionary *)m_Marks[i].GetParam();
653             if (pDict->KeyExist(FX_BSTRC("MCID"))) {
654                 return pDict->GetInteger(FX_BSTRC("MCID"));
655             }
656         }
657     }
658     return -1;
659 }
660 void CPDF_ContentMarkData::AddMark(const CFX_ByteString& name, CPDF_Dictionary* pDict, FX_BOOL bDirect)
661 {
662     CPDF_ContentMarkItem& item = m_Marks.Add();
663     item.SetName(name);
664     if (pDict == NULL) {
665         return;
666     }
667     item.SetParam(bDirect ? CPDF_ContentMarkItem::DirectDict : CPDF_ContentMarkItem::PropertiesDict,
668                   bDirect ? pDict->Clone() : pDict);
669 }
670 void CPDF_ContentMarkData::DeleteLastMark()
671 {
672     int size = m_Marks.GetSize();
673     if (size == 0) {
674         return;
675     }
676     m_Marks.RemoveAt(size - 1);
677 }
678 FX_BOOL CPDF_ContentMark::HasMark(const CFX_ByteStringC& mark) const
679 {
680     if (m_pObject == NULL) {
681         return FALSE;
682     }
683     for (int i = 0; i < m_pObject->CountItems(); i ++) {
684         CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
685         if (item.GetName() == mark) {
686             return TRUE;
687         }
688     }
689     return FALSE;
690 }
691 FX_BOOL CPDF_ContentMark::LookupMark(const CFX_ByteStringC& mark, CPDF_Dictionary*& pDict) const
692 {
693     if (m_pObject == NULL) {
694         return FALSE;
695     }
696     for (int i = 0; i < m_pObject->CountItems(); i ++) {
697         CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
698         if (item.GetName() == mark) {
699             pDict = NULL;
700             if (item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict ||
701                     item.GetParamType() == CPDF_ContentMarkItem::DirectDict) {
702                 pDict = (CPDF_Dictionary*)item.GetParam();
703             }
704             return TRUE;
705         }
706     }
707     return FALSE;
708 }