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