178db75cf8feb5ce6639cf3510d59be792c62a9e
[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         if (m_pTextList[i]) {
42             delete m_pTextList[i];
43         }
44     if (m_pTextList) {
45         FX_Free(m_pTextList);
46     }
47 }
48 CPDF_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(uint8_t, alloc_size);
64         FXSYS_memcpy(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 }
84 void 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(uint8_t, alloc_size);
92     }
93     if (text_count) {
94         m_TextCount = text_count;
95         m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);
96     }
97 }
98 CPDF_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 }
137 void 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         uint8_t* pNewType = FX_Alloc(uint8_t, pData->m_PathCount + 8);
159         FXSYS_memcpy(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] = (uint8_t)type;
168     pData->m_PathCount ++;
169 }
170 void 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_memmove(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
185 void 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_memcpy(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 }
206 void 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 }
218 CPDF_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 }
225 void 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 }
231 void 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 }
236 void 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 }
241 void 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 }
255 void 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 }
267 void 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 }
279 CPDF_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 }
292 CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src)
293 {
294     if (this == &src) {
295         return;
296     }
297     FXSYS_memcpy(this, &src, sizeof(CPDF_TextStateData));
298     if (m_pDocument && m_pFont) {
299         m_pFont = m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);
300     }
301 }
302 CPDF_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 }
311 void 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 }
324 FX_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 }
331 FX_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 }
338 FX_FLOAT CPDF_TextState::GetBaselineAngle() const
339 {
340     FX_FLOAT* m_Matrix = GetMatrix();
341     return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);
342 }
343 FX_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 }
349 CPDF_GeneralStateData::CPDF_GeneralStateData()
350 {
351     FXSYS_memset(this, 0, sizeof(CPDF_GeneralStateData));
352     FXSYS_strcpy((FX_CHAR*)m_BlendMode, "Normal");
353     m_StrokeAlpha = 1.0f;
354     m_FillAlpha = 1.0f;
355     m_Flatness = 1.0f;
356     m_Matrix.SetIdentity();
357 }
358 CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src)
359 {
360     FXSYS_memcpy(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 }
369 CPDF_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 }
379 static int GetBlendType(const CFX_ByteStringC& 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 }
420 void CPDF_GeneralStateData::SetBlendMode(const CFX_ByteStringC& blend_mode)
421 {
422     if (blend_mode.GetLength() > 15) {
423         return;
424     }
425     FXSYS_memcpy(m_BlendMode, blend_mode.GetPtr(), blend_mode.GetLength());
426     m_BlendMode[blend_mode.GetLength()] = 0;
427     m_BlendType = ::GetBlendType(blend_mode);
428 }
429 int 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 }
443 void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri)
444 {
445     GetModify()->m_RenderIntent = RI_StringToId(ri);
446 }
447 CPDF_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 }
454 CPDF_AllStates::~CPDF_AllStates()
455 {
456 }
457 void 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 }
471 void 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 }
480 void 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_memcpy(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 }
615 CPDF_ContentMarkItem::CPDF_ContentMarkItem()
616 {
617     m_ParamType = None;
618 }
619 CPDF_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 }
629 CPDF_ContentMarkItem::~CPDF_ContentMarkItem()
630 {
631     if (m_ParamType == DirectDict && m_pParam) {
632         ((CPDF_Dictionary*)m_pParam)->Release();
633     }
634 }
635 FX_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 }
642 CPDF_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 }
648 int 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 }
662 void 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 }
672 void CPDF_ContentMarkData::DeleteLastMark()
673 {
674     int size = m_Marks.GetSize();
675     if (size == 0) {
676         return;
677     }
678     m_Marks.RemoveAt(size - 1);
679 }
680 FX_BOOL CPDF_ContentMark::HasMark(const CFX_ByteStringC& 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 }
693 FX_BOOL CPDF_ContentMark::LookupMark(const CFX_ByteStringC& 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 }