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