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