Check the number of component in ICCBased colorspace
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_graph_state.cpp
index e9115e6..99bb5b8 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../../include/fpdfapi/fpdf_page.h"\r
-#include "../../../include/fpdfapi/fpdf_pageobj.h"\r
-#include "../../../include/fpdfapi/fpdf_module.h"\r
-#include "../../../include/fpdfapi/fpdf_render.h"\r
-#include "pageint.h"\r
-#include "../fpdf_render/render_int.h"\r
-void CPDF_GraphicStates::DefaultStates()\r
-{\r
-    m_ColorState.New()->Default();\r
-}\r
-void CPDF_GraphicStates::CopyStates(const CPDF_GraphicStates& src)\r
-{\r
-    m_ClipPath = src.m_ClipPath;\r
-    m_GraphState = src.m_GraphState;\r
-    m_ColorState = src.m_ColorState;\r
-    m_TextState = src.m_TextState;\r
-    m_GeneralState = src.m_GeneralState;\r
-}\r
-CPDF_ClipPathData::CPDF_ClipPathData()\r
-{\r
-    m_PathCount = 0;\r
-    m_pPathList = NULL;\r
-    m_pTypeList = NULL;\r
-    m_TextCount = 0;\r
-    m_pTextList = NULL;\r
-}\r
-CPDF_ClipPathData::~CPDF_ClipPathData()\r
-{\r
-    int i;\r
-    if (m_pPathList) {\r
-        FX_DELETE_VECTOR(m_pPathList, CPDF_Path, m_PathCount);\r
-    }\r
-    if (m_pTypeList) {\r
-        FX_Free(m_pTypeList);\r
-    }\r
-    for (i = m_TextCount - 1; i > -1; i --)\r
-        if (m_pTextList[i]) {\r
-            delete m_pTextList[i];\r
-        }\r
-    if (m_pTextList) {\r
-        FX_Free(m_pTextList);\r
-    }\r
-}\r
-CPDF_ClipPathData::CPDF_ClipPathData(const CPDF_ClipPathData& src)\r
-{\r
-    m_pPathList = NULL;\r
-    m_pPathList = NULL;\r
-    m_pTextList = NULL;\r
-    m_PathCount = src.m_PathCount;\r
-    if (m_PathCount) {\r
-        int alloc_size = m_PathCount;\r
-        if (alloc_size % 8) {\r
-            alloc_size += 8 - (alloc_size % 8);\r
-        }\r
-        FX_NEW_VECTOR(m_pPathList, CPDF_Path, alloc_size);\r
-        for (int i = 0; i < m_PathCount; i ++) {\r
-            m_pPathList[i] = src.m_pPathList[i];\r
-        }\r
-        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);\r
-        FXSYS_memcpy32(m_pTypeList, src.m_pTypeList, m_PathCount);\r
-    } else {\r
-        m_pPathList = NULL;\r
-        m_pTypeList = NULL;\r
-    }\r
-    m_TextCount = src.m_TextCount;\r
-    if (m_TextCount) {\r
-        m_pTextList = FX_Alloc(CPDF_TextObject*, m_TextCount);\r
-        FXSYS_memset32(m_pTextList, 0, sizeof(CPDF_TextObject*) * m_TextCount);\r
-        for (int i = 0; i < m_TextCount; i ++) {\r
-            if (src.m_pTextList[i]) {\r
-                m_pTextList[i] = FX_NEW CPDF_TextObject;\r
-                m_pTextList[i]->Copy(src.m_pTextList[i]);\r
-            } else {\r
-                m_pTextList[i] = NULL;\r
-            }\r
-        }\r
-    } else {\r
-        m_pTextList = NULL;\r
-    }\r
-}\r
-void CPDF_ClipPathData::SetCount(int path_count, int text_count)\r
-{\r
-    ASSERT(m_TextCount == 0 && m_PathCount == 0);\r
-    if (path_count) {\r
-        m_PathCount = path_count;\r
-        int alloc_size = (path_count + 7) / 8 * 8;\r
-        FX_NEW_VECTOR(m_pPathList, CPDF_Path, alloc_size);\r
-        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);\r
-    }\r
-    if (text_count) {\r
-        m_TextCount = text_count;\r
-        m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);\r
-        FXSYS_memset32(m_pTextList, 0, sizeof(void*) * text_count);\r
-    }\r
-}\r
-CPDF_Rect CPDF_ClipPath::GetClipBox() const\r
-{\r
-    CPDF_Rect rect;\r
-    FX_BOOL bStarted = FALSE;\r
-    int count = GetPathCount();\r
-    if (count) {\r
-        rect = GetPath(0).GetBoundingBox();\r
-        for (int i = 1; i < count; i ++) {\r
-            CPDF_Rect path_rect = GetPath(i).GetBoundingBox();\r
-            rect.Intersect(path_rect);\r
-        }\r
-        bStarted = TRUE;\r
-    }\r
-    count = GetTextCount();\r
-    if (count) {\r
-        CPDF_Rect layer_rect;\r
-        FX_BOOL bLayerStarted = FALSE;\r
-        for (int i = 0; i < count; i ++) {\r
-            CPDF_TextObject* pTextObj = GetText(i);\r
-            if (pTextObj == NULL) {\r
-                if (!bStarted) {\r
-                    rect = layer_rect;\r
-                    bStarted = TRUE;\r
-                } else {\r
-                    rect.Intersect(layer_rect);\r
-                }\r
-                bLayerStarted = FALSE;\r
-            } else {\r
-                if (!bLayerStarted) {\r
-                    layer_rect = pTextObj->GetBBox(NULL);\r
-                    bLayerStarted = TRUE;\r
-                } else {\r
-                    layer_rect.Union(pTextObj->GetBBox(NULL));\r
-                }\r
-            }\r
-        }\r
-    }\r
-    return rect;\r
-}\r
-void CPDF_ClipPath::AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)\r
-{\r
-    CPDF_ClipPathData* pData = GetModify();\r
-    if (pData->m_PathCount && bAutoMerge) {\r
-        CPDF_Path old_path = pData->m_pPathList[pData->m_PathCount - 1];\r
-        if (old_path.IsRect()) {\r
-            CPDF_Rect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),\r
-                               old_path.GetPointX(2), old_path.GetPointY(2));\r
-            CPDF_Rect new_rect = path.GetBoundingBox();\r
-            if (old_rect.Contains(new_rect)) {\r
-                pData->m_PathCount --;\r
-                pData->m_pPathList[pData->m_PathCount].SetNull();\r
-            }\r
-        }\r
-    }\r
-    if (pData->m_PathCount % 8 == 0) {\r
-        CPDF_Path* pNewPath;\r
-        FX_NEW_VECTOR(pNewPath, CPDF_Path, pData->m_PathCount + 8);\r
-        for (int i = 0; i < pData->m_PathCount; i ++) {\r
-            pNewPath[i] = pData->m_pPathList[i];\r
-        }\r
-        if (pData->m_pPathList) {\r
-            FX_DELETE_VECTOR(pData->m_pPathList, CPDF_Path, pData->m_PathCount);\r
-        }\r
-        FX_BYTE* pNewType = FX_Alloc(FX_BYTE, pData->m_PathCount + 8);\r
-        FXSYS_memcpy32(pNewType, pData->m_pTypeList, pData->m_PathCount);\r
-        if (pData->m_pTypeList) {\r
-            FX_Free(pData->m_pTypeList);\r
-        }\r
-        pData->m_pPathList = pNewPath;\r
-        pData->m_pTypeList = pNewType;\r
-    }\r
-    pData->m_pPathList[pData->m_PathCount] = path;\r
-    pData->m_pTypeList[pData->m_PathCount] = (FX_BYTE)type;\r
-    pData->m_PathCount ++;\r
-}\r
-void CPDF_ClipPath::DeletePath(int index)\r
-{\r
-    CPDF_ClipPathData* pData = GetModify();\r
-    if (index >= pData->m_PathCount) {\r
-        return;\r
-    }\r
-    pData->m_pPathList[index].SetNull();\r
-    for (int i = index; i < pData->m_PathCount - 1; i ++) {\r
-        pData->m_pPathList[i] = pData->m_pPathList[i + 1];\r
-    }\r
-    pData->m_pPathList[pData->m_PathCount - 1].SetNull();\r
-    FXSYS_memmove32(pData->m_pTypeList + index, pData->m_pTypeList + index + 1, pData->m_PathCount - index - 1);\r
-    pData->m_PathCount --;\r
-}\r
-#define FPDF_CLIPPATH_MAX_TEXTS 1024\r
-void CPDF_ClipPath::AppendTexts(CPDF_TextObject** pTexts, int count)\r
-{\r
-    CPDF_ClipPathData* pData = GetModify();\r
-    if (pData->m_TextCount + count > FPDF_CLIPPATH_MAX_TEXTS) {\r
-        for (int i = 0; i < count; i ++) {\r
-            pTexts[i]->Release();\r
-        }\r
-        return;\r
-    }\r
-    CPDF_TextObject** pNewList = FX_Alloc(CPDF_TextObject*, pData->m_TextCount + count + 1);\r
-    if (pData->m_pTextList) {\r
-        FXSYS_memcpy32(pNewList, pData->m_pTextList, pData->m_TextCount * sizeof(CPDF_TextObject*));\r
-        FX_Free(pData->m_pTextList);\r
-    }\r
-    pData->m_pTextList = pNewList;\r
-    for (int i = 0; i < count; i ++) {\r
-        pData->m_pTextList[pData->m_TextCount + i] = pTexts[i];\r
-    }\r
-    pData->m_pTextList[pData->m_TextCount + count] = NULL;\r
-    pData->m_TextCount += count + 1;\r
-}\r
-void CPDF_ClipPath::Transform(const CPDF_Matrix& matrix)\r
-{\r
-    CPDF_ClipPathData* pData = GetModify();\r
-    int i;\r
-    for (i = 0; i < pData->m_PathCount; i ++) {\r
-        pData->m_pPathList[i].Transform(&matrix);\r
-    }\r
-    for (i = 0; i < pData->m_TextCount; i ++)\r
-        if (pData->m_pTextList[i]) {\r
-            pData->m_pTextList[i]->Transform(matrix);\r
-        }\r
-}\r
-CPDF_ColorStateData::CPDF_ColorStateData(const CPDF_ColorStateData& src)\r
-{\r
-    m_FillColor.Copy(&src.m_FillColor);\r
-    m_FillRGB = src.m_FillRGB;\r
-    m_StrokeColor.Copy(&src.m_StrokeColor);\r
-    m_StrokeRGB = src.m_StrokeRGB;\r
-}\r
-void CPDF_ColorStateData::Default()\r
-{\r
-    m_FillRGB = m_StrokeRGB = 0;\r
-    m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));\r
-    m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));\r
-}\r
-void CPDF_ColorState::SetFillColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)\r
-{\r
-    CPDF_ColorStateData* pData = GetModify();\r
-    SetColor(pData->m_FillColor, pData->m_FillRGB, pCS, pValue, nValues);\r
-}\r
-void CPDF_ColorState::SetStrokeColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)\r
-{\r
-    CPDF_ColorStateData* pData = GetModify();\r
-    SetColor(pData->m_StrokeColor, pData->m_StrokeRGB, pCS, pValue, nValues);\r
-}\r
-void CPDF_ColorState::SetColor(CPDF_Color& color, FX_DWORD& rgb, CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)\r
-{\r
-    if (pCS) {\r
-        color.SetColorSpace(pCS);\r
-    } else if (color.IsNull()) {\r
-        color.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));\r
-    }\r
-    if (color.m_pCS->CountComponents() > nValues) {\r
-        return;\r
-    }\r
-    color.SetValue(pValue);\r
-    int R, G, B;\r
-    rgb = color.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;\r
-}\r
-void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)\r
-{\r
-    CPDF_ColorStateData* pData = GetModify();\r
-    pData->m_FillColor.SetValue(pPattern, pValue, nValues);\r
-    int R, G, B;\r
-    FX_BOOL ret = pData->m_FillColor.GetRGB(R, G, B);\r
-    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {\r
-        pData->m_FillRGB = 0x00BFBFBF;\r
-        return;\r
-    }\r
-    pData->m_FillRGB = ret ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;\r
-}\r
-void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)\r
-{\r
-    CPDF_ColorStateData* pData = GetModify();\r
-    pData->m_StrokeColor.SetValue(pPattern, pValue, nValues);\r
-    int R, G, B;\r
-    FX_BOOL ret = pData->m_StrokeColor.GetRGB(R, G, B);\r
-    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {\r
-        pData->m_StrokeRGB = 0x00BFBFBF;\r
-        return;\r
-    }\r
-    pData->m_StrokeRGB = pData->m_StrokeColor.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;\r
-}\r
-CPDF_TextStateData::CPDF_TextStateData()\r
-{\r
-    m_pFont = NULL;\r
-    m_FontSize = 1.0f;\r
-    m_WordSpace = 0;\r
-    m_CharSpace = 0;\r
-    m_TextMode = 0;\r
-    m_Matrix[0] = m_Matrix[3] = 1.0f;\r
-    m_Matrix[1] = m_Matrix[2] = 0;\r
-    m_CTM[0] = m_CTM[3] = 1.0f;\r
-    m_CTM[1] = m_CTM[2] = 0;\r
-}\r
-CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src)\r
-{\r
-    FXSYS_memcpy32(this, &src, sizeof(CPDF_TextStateData));\r
-    if (m_pFont && m_pFont->m_pDocument) {\r
-        m_pFont = m_pFont->m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);\r
-    }\r
-}\r
-CPDF_TextStateData::~CPDF_TextStateData()\r
-{\r
-    CPDF_Font* pFont = m_pFont;\r
-    if (pFont && pFont->m_pDocument) {\r
-        pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict());\r
-    }\r
-}\r
-void CPDF_TextState::SetFont(CPDF_Font* pFont)\r
-{\r
-    CPDF_Font*& pStateFont = GetModify()->m_pFont;\r
-    CPDF_DocPageData* pDocPageData = NULL;\r
-    if (pStateFont && pStateFont->m_pDocument) {\r
-        pDocPageData = pStateFont->m_pDocument->GetPageData();\r
-        pDocPageData->ReleaseFont(pStateFont->GetFontDict());\r
-    }\r
-    pStateFont = pFont;\r
-}\r
-FX_FLOAT CPDF_TextState::GetFontSizeV() const\r
-{\r
-    FX_FLOAT* pMatrix = GetMatrix();\r
-    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[1], pMatrix[3]);\r
-    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());\r
-    return (FX_FLOAT)FXSYS_fabs(size);\r
-}\r
-FX_FLOAT CPDF_TextState::GetFontSizeH() const\r
-{\r
-    FX_FLOAT* pMatrix = GetMatrix();\r
-    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[0], pMatrix[2]);\r
-    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());\r
-    return (FX_FLOAT)FXSYS_fabs(size);\r
-}\r
-FX_FLOAT CPDF_TextState::GetBaselineAngle() const\r
-{\r
-    FX_FLOAT* m_Matrix = GetMatrix();\r
-    return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);\r
-}\r
-FX_FLOAT CPDF_TextState::GetShearAngle() const\r
-{\r
-    FX_FLOAT* m_Matrix = GetMatrix();\r
-    FX_FLOAT shear_angle = FXSYS_atan2(m_Matrix[1], m_Matrix[3]);\r
-    return GetBaselineAngle() + shear_angle;\r
-}\r
-CPDF_GeneralStateData::CPDF_GeneralStateData()\r
-{\r
-    FXSYS_memset32(this, 0, sizeof(CPDF_GeneralStateData));\r
-    FXSYS_strcpy((FX_LPSTR)m_BlendMode, (FX_LPCSTR)"Normal");\r
-    m_StrokeAlpha = 1.0f;\r
-    m_FillAlpha = 1.0f;\r
-    m_Flatness = 1.0f;\r
-    m_Matrix.SetIdentity();\r
-}\r
-CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src)\r
-{\r
-    FXSYS_memcpy32(this, &src, sizeof(CPDF_GeneralStateData));\r
-    if (src.m_pTransferFunc && src.m_pTransferFunc->m_pPDFDoc) {\r
-        CPDF_DocRenderData* pDocCache = src.m_pTransferFunc->m_pPDFDoc->GetRenderData();\r
-        if (!pDocCache) {\r
-            return;\r
-        }\r
-        m_pTransferFunc = pDocCache->GetTransferFunc(m_pTR);\r
-    }\r
-}\r
-CPDF_GeneralStateData::~CPDF_GeneralStateData()\r
-{\r
-    if (m_pTransferFunc && m_pTransferFunc->m_pPDFDoc) {\r
-        CPDF_DocRenderData* pDocCache = m_pTransferFunc->m_pPDFDoc->GetRenderData();\r
-        if (!pDocCache) {\r
-            return;\r
-        }\r
-        pDocCache->ReleaseTransferFunc(m_pTR);\r
-    }\r
-}\r
-static int GetBlendType(FX_BSTR mode)\r
-{\r
-    switch (mode.GetID()) {\r
-        case FXBSTR_ID('N', 'o', 'r', 'm'):\r
-        case FXBSTR_ID('C', 'o', 'm', 'p'):\r
-            return FXDIB_BLEND_NORMAL;\r
-        case FXBSTR_ID('M', 'u', 'l', 't'):\r
-            return FXDIB_BLEND_MULTIPLY;\r
-        case FXBSTR_ID('S', 'c', 'r', 'e'):\r
-            return FXDIB_BLEND_SCREEN;\r
-        case FXBSTR_ID('O', 'v', 'e', 'r'):\r
-            return FXDIB_BLEND_OVERLAY;\r
-        case FXBSTR_ID('D', 'a', 'r', 'k'):\r
-            return FXDIB_BLEND_DARKEN;\r
-        case FXBSTR_ID('L', 'i', 'g', 'h'):\r
-            return FXDIB_BLEND_LIGHTEN;\r
-        case FXBSTR_ID('C', 'o', 'l', 'o'):\r
-            if (mode.GetLength() == 10) {\r
-                return FXDIB_BLEND_COLORDODGE;\r
-            }\r
-            if (mode.GetLength() == 9) {\r
-                return FXDIB_BLEND_COLORBURN;\r
-            }\r
-            return FXDIB_BLEND_COLOR;\r
-        case FXBSTR_ID('H', 'a', 'r', 'd'):\r
-            return FXDIB_BLEND_HARDLIGHT;\r
-        case FXBSTR_ID('S', 'o', 'f', 't'):\r
-            return FXDIB_BLEND_SOFTLIGHT;\r
-        case FXBSTR_ID('D', 'i', 'f', 'f'):\r
-            return FXDIB_BLEND_DIFFERENCE;\r
-        case FXBSTR_ID('E', 'x', 'c', 'l'):\r
-            return FXDIB_BLEND_EXCLUSION;\r
-        case FXBSTR_ID('H', 'u', 'e', 0):\r
-            return FXDIB_BLEND_HUE;\r
-        case FXBSTR_ID('S', 'a', 't', 'u'):\r
-            return FXDIB_BLEND_SATURATION;\r
-        case FXBSTR_ID('L', 'u', 'm', 'i'):\r
-            return FXDIB_BLEND_LUMINOSITY;\r
-    }\r
-    return FXDIB_BLEND_NORMAL;\r
-}\r
-void CPDF_GeneralStateData::SetBlendMode(FX_BSTR blend_mode)\r
-{\r
-    if (blend_mode.GetLength() > 15) {\r
-        return;\r
-    }\r
-    FXSYS_memcpy32(m_BlendMode, (FX_LPCBYTE)blend_mode, blend_mode.GetLength());\r
-    m_BlendMode[blend_mode.GetLength()] = 0;\r
-    m_BlendType = ::GetBlendType(blend_mode);\r
-}\r
-int RI_StringToId(const CFX_ByteString& ri)\r
-{\r
-    FX_DWORD id = ri.GetID();\r
-    if (id == FXBSTR_ID('A', 'b', 's', 'o')) {\r
-        return 1;\r
-    }\r
-    if (id == FXBSTR_ID('S', 'a', 't', 'u')) {\r
-        return 2;\r
-    }\r
-    if (id == FXBSTR_ID('P', 'e', 'r', 'c')) {\r
-        return 3;\r
-    }\r
-    return 0;\r
-}\r
-void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri)\r
-{\r
-    GetModify()->m_RenderIntent = RI_StringToId(ri);\r
-}\r
-CPDF_AllStates::CPDF_AllStates()\r
-{\r
-    m_TextX = m_TextY = m_TextLineX = m_TextLineY = 0;\r
-    m_TextLeading = 0;\r
-    m_TextRise = 0;\r
-    m_TextHorzScale = 1.0f;\r
-}\r
-CPDF_AllStates::~CPDF_AllStates()\r
-{\r
-}\r
-void CPDF_AllStates::Copy(const CPDF_AllStates& src)\r
-{\r
-    CopyStates(src);\r
-    m_TextMatrix.Copy(src.m_TextMatrix);\r
-    m_ParentMatrix.Copy(src.m_ParentMatrix);\r
-    m_CTM.Copy(src.m_CTM);\r
-    m_TextX = src.m_TextX;\r
-    m_TextY = src.m_TextY;\r
-    m_TextLineX = src.m_TextLineX;\r
-    m_TextLineY = src.m_TextLineY;\r
-    m_TextLeading = src.m_TextLeading;\r
-    m_TextRise = src.m_TextRise;\r
-    m_TextHorzScale = src.m_TextHorzScale;\r
-}\r
-void CPDF_AllStates::SetLineDash(CPDF_Array* pArray, FX_FLOAT phase, FX_FLOAT scale)\r
-{\r
-    CFX_GraphStateData* pData = m_GraphState.GetModify();\r
-    pData->m_DashPhase = FXSYS_Mul(phase, scale);\r
-    pData->SetDashCount(pArray->GetCount());\r
-    for (FX_DWORD i = 0; i < pArray->GetCount(); i ++) {\r
-        pData->m_DashArray[i] = FXSYS_Mul(pArray->GetNumber(i), scale);\r
-    }\r
-}\r
-void CPDF_AllStates::ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser)\r
-{\r
-    CPDF_GeneralStateData* pGeneralState = m_GeneralState.GetModify();\r
-    FX_POSITION pos = pGS->GetStartPos();\r
-    while (pos) {\r
-        CFX_ByteString key_str;\r
-        CPDF_Object* pObject = pGS->GetNextElement(pos, key_str)->GetDirect();\r
-        if (pObject == NULL) {\r
-            continue;\r
-        }\r
-        FX_DWORD key = key_str.GetID();\r
-        switch (key) {\r
-            case FXBSTR_ID('L', 'W', 0, 0):\r
-                m_GraphState.GetModify()->m_LineWidth = pObject->GetNumber();\r
-                break;\r
-            case FXBSTR_ID('L', 'C', 0, 0):\r
-                m_GraphState.GetModify()->m_LineCap = (CFX_GraphStateData::LineCap)pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('L', 'J', 0, 0):\r
-                m_GraphState.GetModify()->m_LineJoin = (CFX_GraphStateData::LineJoin)pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('M', 'L', 0, 0):\r
-                m_GraphState.GetModify()->m_MiterLimit = pObject->GetNumber();\r
-                break;\r
-            case FXBSTR_ID('D', 0, 0, 0):      {\r
-                    if (pObject->GetType() != PDFOBJ_ARRAY) {\r
-                        break;\r
-                    }\r
-                    CPDF_Array* pDash = (CPDF_Array*)pObject;\r
-                    CPDF_Array* pArray = pDash->GetArray(0);\r
-                    if (pArray == NULL) {\r
-                        break;\r
-                    }\r
-                    SetLineDash(pArray, pDash->GetNumber(1), 1.0f);\r
-                    break;\r
-                }\r
-            case FXBSTR_ID('R', 'I', 0, 0):\r
-                m_GeneralState.SetRenderIntent(pObject->GetString());\r
-                break;\r
-            case FXBSTR_ID('F', 'o', 'n', 't'):        {\r
-                    if (pObject->GetType() != PDFOBJ_ARRAY) {\r
-                        break;\r
-                    }\r
-                    CPDF_Array* pFont = (CPDF_Array*)pObject;\r
-                    m_TextState.GetModify()->m_FontSize = pFont->GetNumber(1);\r
-                    m_TextState.SetFont(pParser->FindFont(pFont->GetString(0)));\r
-                    break;\r
-                }\r
-            case FXBSTR_ID('T', 'R', 0, 0):\r
-                if (pGS->KeyExist(FX_BSTRC("TR2"))) {\r
-                    continue;\r
-                }\r
-            case FXBSTR_ID('T', 'R', '2', 0):\r
-                if (pObject && pObject->GetType() != PDFOBJ_NAME) {\r
-                    pGeneralState->m_pTR = pObject;\r
-                } else {\r
-                    pGeneralState->m_pTR = NULL;\r
-                }\r
-                break;\r
-            case FXBSTR_ID('B', 'M', 0, 0):    {\r
-                    CFX_ByteString mode;\r
-                    if (pObject->GetType() == PDFOBJ_ARRAY) {\r
-                        mode = ((CPDF_Array*)pObject)->GetString(0);\r
-                    } else {\r
-                        mode = pObject->GetString();\r
-                    }\r
-                    pGeneralState->SetBlendMode(mode);\r
-                    if (pGeneralState->m_BlendType > FXDIB_BLEND_MULTIPLY) {\r
-                        pParser->m_pObjectList->m_bBackgroundAlphaNeeded = TRUE;\r
-                    }\r
-                    break;\r
-                }\r
-            case FXBSTR_ID('S', 'M', 'a', 's'):\r
-                if (pObject && pObject->GetType() == PDFOBJ_DICTIONARY) {\r
-                    pGeneralState->m_pSoftMask = pObject;\r
-                    FXSYS_memcpy32(pGeneralState->m_SMaskMatrix, &pParser->m_pCurStates->m_CTM, sizeof(CPDF_Matrix));\r
-                } else {\r
-                    pGeneralState->m_pSoftMask = NULL;\r
-                }\r
-                break;\r
-            case FXBSTR_ID('C', 'A', 0, 0):\r
-                pGeneralState->m_StrokeAlpha = PDF_ClipFloat(pObject->GetNumber());\r
-                break;\r
-            case FXBSTR_ID('c', 'a', 0, 0):\r
-                pGeneralState->m_FillAlpha = PDF_ClipFloat(pObject->GetNumber());\r
-                break;\r
-            case FXBSTR_ID('O', 'P', 0, 0):\r
-                pGeneralState->m_StrokeOP = pObject->GetInteger();\r
-                if (!pGS->KeyExist(FX_BSTRC("op"))) {\r
-                    pGeneralState->m_FillOP = pObject->GetInteger();\r
-                }\r
-                break;\r
-            case FXBSTR_ID('o', 'p', 0, 0):\r
-                pGeneralState->m_FillOP = pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('O', 'P', 'M', 0):\r
-                pGeneralState->m_OPMode = pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('B', 'G', 0, 0):\r
-                if (pGS->KeyExist(FX_BSTRC("BG2"))) {\r
-                    continue;\r
-                }\r
-            case FXBSTR_ID('B', 'G', '2', 0):\r
-                pGeneralState->m_pBG = pObject;\r
-                break;\r
-            case FXBSTR_ID('U', 'C', 'R', 0):\r
-                if (pGS->KeyExist(FX_BSTRC("UCR2"))) {\r
-                    continue;\r
-                }\r
-            case FXBSTR_ID('U', 'C', 'R', '2'):\r
-                pGeneralState->m_pUCR = pObject;\r
-                break;\r
-            case FXBSTR_ID('H', 'T', 0, 0):\r
-                pGeneralState->m_pHT = pObject;\r
-                break;\r
-            case FXBSTR_ID('F', 'L', 0, 0):\r
-                pGeneralState->m_Flatness = pObject->GetNumber();\r
-                break;\r
-            case FXBSTR_ID('S', 'M', 0, 0):\r
-                pGeneralState->m_Smoothness = pObject->GetNumber();\r
-                break;\r
-            case FXBSTR_ID('S', 'A', 0, 0):\r
-                pGeneralState->m_StrokeAdjust = pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('A', 'I', 'S', 0):\r
-                pGeneralState->m_AlphaSource = pObject->GetInteger();\r
-                break;\r
-            case FXBSTR_ID('T', 'K', 0, 0):\r
-                pGeneralState->m_TextKnockout = pObject->GetInteger();\r
-                break;\r
-        }\r
-    }\r
-    pGeneralState->m_Matrix = m_CTM;\r
-}\r
-CPDF_ContentMarkItem::CPDF_ContentMarkItem()\r
-{\r
-    m_ParamType = None;\r
-}\r
-CPDF_ContentMarkItem::CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src)\r
-{\r
-    m_MarkName = src.m_MarkName;\r
-    m_ParamType = src.m_ParamType;\r
-    if (m_ParamType == DirectDict) {\r
-        m_pParam = ((CPDF_Dictionary*)src.m_pParam)->Clone();\r
-    } else {\r
-        m_pParam = src.m_pParam;\r
-    }\r
-}\r
-CPDF_ContentMarkItem::~CPDF_ContentMarkItem()\r
-{\r
-    if (m_ParamType == DirectDict) {\r
-        ((CPDF_Dictionary*)m_pParam)->Release();\r
-    }\r
-}\r
-FX_BOOL        CPDF_ContentMarkItem::HasMCID() const\r
-{\r
-    if (m_pParam && (m_ParamType == DirectDict || m_ParamType == PropertiesDict)) {\r
-        return ((CPDF_Dictionary *)m_pParam)->KeyExist(FX_BSTRC("MCID"));\r
-    }\r
-    return FALSE;\r
-}\r
-CPDF_ContentMarkData::CPDF_ContentMarkData(const CPDF_ContentMarkData& src)\r
-{\r
-    for (int i = 0; i < src.m_Marks.GetSize(); i ++) {\r
-        m_Marks.Add(src.m_Marks[i]);\r
-    }\r
-}\r
-int CPDF_ContentMarkData::GetMCID() const\r
-{\r
-    CPDF_ContentMarkItem::ParamType type = CPDF_ContentMarkItem::None;\r
-    for (int i = 0; i < m_Marks.GetSize(); i ++) {\r
-        type = m_Marks[i].GetParamType();\r
-        if (type == CPDF_ContentMarkItem::PropertiesDict || type == CPDF_ContentMarkItem::DirectDict) {\r
-            CPDF_Dictionary *pDict = (CPDF_Dictionary *)m_Marks[i].GetParam();\r
-            if (pDict->KeyExist(FX_BSTRC("MCID"))) {\r
-                return pDict->GetInteger(FX_BSTRC("MCID"));\r
-            }\r
-        }\r
-    }\r
-    return -1;\r
-}\r
-void CPDF_ContentMarkData::AddMark(const CFX_ByteString& name, CPDF_Dictionary* pDict, FX_BOOL bDirect)\r
-{\r
-    CPDF_ContentMarkItem& item = m_Marks.Add();\r
-    item.SetName(name);\r
-    if (pDict == NULL) {\r
-        return;\r
-    }\r
-    item.SetParam(bDirect ? CPDF_ContentMarkItem::DirectDict : CPDF_ContentMarkItem::PropertiesDict,\r
-                  bDirect ? pDict->Clone() : pDict);\r
-}\r
-void CPDF_ContentMarkData::DeleteLastMark()\r
-{\r
-    int size = m_Marks.GetSize();\r
-    if (size == 0) {\r
-        return;\r
-    }\r
-    m_Marks.RemoveAt(size - 1);\r
-}\r
-FX_BOOL CPDF_ContentMark::HasMark(FX_BSTR mark) const\r
-{\r
-    if (m_pObject == NULL) {\r
-        return FALSE;\r
-    }\r
-    for (int i = 0; i < m_pObject->CountItems(); i ++) {\r
-        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);\r
-        if (item.GetName() == mark) {\r
-            return TRUE;\r
-        }\r
-    }\r
-    return FALSE;\r
-}\r
-FX_BOOL CPDF_ContentMark::LookupMark(FX_BSTR mark, CPDF_Dictionary*& pDict) const\r
-{\r
-    if (m_pObject == NULL) {\r
-        return FALSE;\r
-    }\r
-    for (int i = 0; i < m_pObject->CountItems(); i ++) {\r
-        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);\r
-        if (item.GetName() == mark) {\r
-            pDict = NULL;\r
-            if (item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict ||\r
-                    item.GetParamType() == CPDF_ContentMarkItem::DirectDict) {\r
-                pDict = (CPDF_Dictionary*)item.GetParam();\r
-            }\r
-            return TRUE;\r
-        }\r
-    }\r
-    return FALSE;\r
-}\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../../include/fpdfapi/fpdf_page.h"
+#include "../../../include/fpdfapi/fpdf_pageobj.h"
+#include "../../../include/fpdfapi/fpdf_module.h"
+#include "../../../include/fpdfapi/fpdf_render.h"
+#include "pageint.h"
+#include "../fpdf_render/render_int.h"
+void CPDF_GraphicStates::DefaultStates()
+{
+    m_ColorState.New()->Default();
+}
+void CPDF_GraphicStates::CopyStates(const CPDF_GraphicStates& src)
+{
+    m_ClipPath = src.m_ClipPath;
+    m_GraphState = src.m_GraphState;
+    m_ColorState = src.m_ColorState;
+    m_TextState = src.m_TextState;
+    m_GeneralState = src.m_GeneralState;
+}
+CPDF_ClipPathData::CPDF_ClipPathData()
+{
+    m_PathCount = 0;
+    m_pPathList = NULL;
+    m_pTypeList = NULL;
+    m_TextCount = 0;
+    m_pTextList = NULL;
+}
+CPDF_ClipPathData::~CPDF_ClipPathData()
+{
+    int i;
+    if (m_pPathList) {
+        FX_DELETE_VECTOR(m_pPathList, CPDF_Path, m_PathCount);
+    }
+    if (m_pTypeList) {
+        FX_Free(m_pTypeList);
+    }
+    for (i = m_TextCount - 1; i > -1; i --)
+        if (m_pTextList[i]) {
+            delete m_pTextList[i];
+        }
+    if (m_pTextList) {
+        FX_Free(m_pTextList);
+    }
+}
+CPDF_ClipPathData::CPDF_ClipPathData(const CPDF_ClipPathData& src)
+{
+    m_pPathList = NULL;
+    m_pPathList = NULL;
+    m_pTextList = NULL;
+    m_PathCount = src.m_PathCount;
+    if (m_PathCount) {
+        int alloc_size = m_PathCount;
+        if (alloc_size % 8) {
+            alloc_size += 8 - (alloc_size % 8);
+        }
+        FX_NEW_VECTOR(m_pPathList, CPDF_Path, alloc_size);
+        for (int i = 0; i < m_PathCount; i ++) {
+            m_pPathList[i] = src.m_pPathList[i];
+        }
+        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);
+        FXSYS_memcpy32(m_pTypeList, src.m_pTypeList, m_PathCount);
+    } else {
+        m_pPathList = NULL;
+        m_pTypeList = NULL;
+    }
+    m_TextCount = src.m_TextCount;
+    if (m_TextCount) {
+        m_pTextList = FX_Alloc(CPDF_TextObject*, m_TextCount);
+        for (int i = 0; i < m_TextCount; i ++) {
+            if (src.m_pTextList[i]) {
+                m_pTextList[i] = FX_NEW CPDF_TextObject;
+                m_pTextList[i]->Copy(src.m_pTextList[i]);
+            } else {
+                m_pTextList[i] = NULL;
+            }
+        }
+    } else {
+        m_pTextList = NULL;
+    }
+}
+void CPDF_ClipPathData::SetCount(int path_count, int text_count)
+{
+    ASSERT(m_TextCount == 0 && m_PathCount == 0);
+    if (path_count) {
+        m_PathCount = path_count;
+        int alloc_size = (path_count + 7) / 8 * 8;
+        FX_NEW_VECTOR(m_pPathList, CPDF_Path, alloc_size);
+        m_pTypeList = FX_Alloc(FX_BYTE, alloc_size);
+    }
+    if (text_count) {
+        m_TextCount = text_count;
+        m_pTextList = FX_Alloc(CPDF_TextObject*, text_count);
+    }
+}
+CPDF_Rect CPDF_ClipPath::GetClipBox() const
+{
+    CPDF_Rect rect;
+    FX_BOOL bStarted = FALSE;
+    int count = GetPathCount();
+    if (count) {
+        rect = GetPath(0).GetBoundingBox();
+        for (int i = 1; i < count; i ++) {
+            CPDF_Rect path_rect = GetPath(i).GetBoundingBox();
+            rect.Intersect(path_rect);
+        }
+        bStarted = TRUE;
+    }
+    count = GetTextCount();
+    if (count) {
+        CPDF_Rect layer_rect;
+        FX_BOOL bLayerStarted = FALSE;
+        for (int i = 0; i < count; i ++) {
+            CPDF_TextObject* pTextObj = GetText(i);
+            if (pTextObj == NULL) {
+                if (!bStarted) {
+                    rect = layer_rect;
+                    bStarted = TRUE;
+                } else {
+                    rect.Intersect(layer_rect);
+                }
+                bLayerStarted = FALSE;
+            } else {
+                if (!bLayerStarted) {
+                    layer_rect = pTextObj->GetBBox(NULL);
+                    bLayerStarted = TRUE;
+                } else {
+                    layer_rect.Union(pTextObj->GetBBox(NULL));
+                }
+            }
+        }
+    }
+    return rect;
+}
+void CPDF_ClipPath::AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge)
+{
+    CPDF_ClipPathData* pData = GetModify();
+    if (pData->m_PathCount && bAutoMerge) {
+        CPDF_Path old_path = pData->m_pPathList[pData->m_PathCount - 1];
+        if (old_path.IsRect()) {
+            CPDF_Rect old_rect(old_path.GetPointX(0), old_path.GetPointY(0),
+                               old_path.GetPointX(2), old_path.GetPointY(2));
+            CPDF_Rect new_rect = path.GetBoundingBox();
+            if (old_rect.Contains(new_rect)) {
+                pData->m_PathCount --;
+                pData->m_pPathList[pData->m_PathCount].SetNull();
+            }
+        }
+    }
+    if (pData->m_PathCount % 8 == 0) {
+        CPDF_Path* pNewPath;
+        FX_NEW_VECTOR(pNewPath, CPDF_Path, pData->m_PathCount + 8);
+        for (int i = 0; i < pData->m_PathCount; i ++) {
+            pNewPath[i] = pData->m_pPathList[i];
+        }
+        if (pData->m_pPathList) {
+            FX_DELETE_VECTOR(pData->m_pPathList, CPDF_Path, pData->m_PathCount);
+        }
+        FX_BYTE* pNewType = FX_Alloc(FX_BYTE, pData->m_PathCount + 8);
+        FXSYS_memcpy32(pNewType, pData->m_pTypeList, pData->m_PathCount);
+        if (pData->m_pTypeList) {
+            FX_Free(pData->m_pTypeList);
+        }
+        pData->m_pPathList = pNewPath;
+        pData->m_pTypeList = pNewType;
+    }
+    pData->m_pPathList[pData->m_PathCount] = path;
+    pData->m_pTypeList[pData->m_PathCount] = (FX_BYTE)type;
+    pData->m_PathCount ++;
+}
+void CPDF_ClipPath::DeletePath(int index)
+{
+    CPDF_ClipPathData* pData = GetModify();
+    if (index >= pData->m_PathCount) {
+        return;
+    }
+    pData->m_pPathList[index].SetNull();
+    for (int i = index; i < pData->m_PathCount - 1; i ++) {
+        pData->m_pPathList[i] = pData->m_pPathList[i + 1];
+    }
+    pData->m_pPathList[pData->m_PathCount - 1].SetNull();
+    FXSYS_memmove32(pData->m_pTypeList + index, pData->m_pTypeList + index + 1, pData->m_PathCount - index - 1);
+    pData->m_PathCount --;
+}
+#define FPDF_CLIPPATH_MAX_TEXTS 1024
+void CPDF_ClipPath::AppendTexts(CPDF_TextObject** pTexts, int count)
+{
+    CPDF_ClipPathData* pData = GetModify();
+    if (pData->m_TextCount + count > FPDF_CLIPPATH_MAX_TEXTS) {
+        for (int i = 0; i < count; i ++) {
+            if (pTexts[i])
+                pTexts[i]->Release();
+        }
+        return;
+    }
+    CPDF_TextObject** pNewList = FX_Alloc(CPDF_TextObject*, pData->m_TextCount + count + 1);
+    if (pData->m_pTextList) {
+        FXSYS_memcpy32(pNewList, pData->m_pTextList, pData->m_TextCount * sizeof(CPDF_TextObject*));
+        FX_Free(pData->m_pTextList);
+    }
+    pData->m_pTextList = pNewList;
+    for (int i = 0; i < count; i ++) {
+        pData->m_pTextList[pData->m_TextCount + i] = pTexts[i];
+    }
+    pData->m_pTextList[pData->m_TextCount + count] = NULL;
+    pData->m_TextCount += count + 1;
+}
+void CPDF_ClipPath::Transform(const CPDF_Matrix& matrix)
+{
+    CPDF_ClipPathData* pData = GetModify();
+    int i;
+    for (i = 0; i < pData->m_PathCount; i ++) {
+        pData->m_pPathList[i].Transform(&matrix);
+    }
+    for (i = 0; i < pData->m_TextCount; i ++)
+        if (pData->m_pTextList[i]) {
+            pData->m_pTextList[i]->Transform(matrix);
+        }
+}
+CPDF_ColorStateData::CPDF_ColorStateData(const CPDF_ColorStateData& src)
+{
+    m_FillColor.Copy(&src.m_FillColor);
+    m_FillRGB = src.m_FillRGB;
+    m_StrokeColor.Copy(&src.m_StrokeColor);
+    m_StrokeRGB = src.m_StrokeRGB;
+}
+void CPDF_ColorStateData::Default()
+{
+    m_FillRGB = m_StrokeRGB = 0;
+    m_FillColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+    m_StrokeColor.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+}
+void CPDF_ColorState::SetFillColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
+{
+    CPDF_ColorStateData* pData = GetModify();
+    SetColor(pData->m_FillColor, pData->m_FillRGB, pCS, pValue, nValues);
+}
+void CPDF_ColorState::SetStrokeColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
+{
+    CPDF_ColorStateData* pData = GetModify();
+    SetColor(pData->m_StrokeColor, pData->m_StrokeRGB, pCS, pValue, nValues);
+}
+void CPDF_ColorState::SetColor(CPDF_Color& color, FX_DWORD& rgb, CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues)
+{
+    if (pCS) {
+        color.SetColorSpace(pCS);
+    } else if (color.IsNull()) {
+        color.SetColorSpace(CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY));
+    }
+    if (color.m_pCS->CountComponents() > nValues) {
+        return;
+    }
+    color.SetValue(pValue);
+    int R, G, B;
+    rgb = color.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
+}
+void CPDF_ColorState::SetFillPattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
+{
+    CPDF_ColorStateData* pData = GetModify();
+    pData->m_FillColor.SetValue(pPattern, pValue, nValues);
+    int R, G, B;
+    FX_BOOL ret = pData->m_FillColor.GetRGB(R, G, B);
+    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
+        pData->m_FillRGB = 0x00BFBFBF;
+        return;
+    }
+    pData->m_FillRGB = ret ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
+}
+void CPDF_ColorState::SetStrokePattern(CPDF_Pattern* pPattern, FX_FLOAT* pValue, int nValues)
+{
+    CPDF_ColorStateData* pData = GetModify();
+    pData->m_StrokeColor.SetValue(pPattern, pValue, nValues);
+    int R, G, B;
+    FX_BOOL ret = pData->m_StrokeColor.GetRGB(R, G, B);
+    if (pPattern->m_PatternType == 1 && ((CPDF_TilingPattern*)pPattern)->m_bColored && !ret) {
+        pData->m_StrokeRGB = 0x00BFBFBF;
+        return;
+    }
+    pData->m_StrokeRGB = pData->m_StrokeColor.GetRGB(R, G, B) ? FXSYS_RGB(R, G, B) : (FX_DWORD) - 1;
+}
+CPDF_TextStateData::CPDF_TextStateData()
+{
+    m_pFont = NULL;
+    m_pDocument = NULL;
+    m_FontSize = 1.0f;
+    m_WordSpace = 0;
+    m_CharSpace = 0;
+    m_TextMode = 0;
+    m_Matrix[0] = m_Matrix[3] = 1.0f;
+    m_Matrix[1] = m_Matrix[2] = 0;
+    m_CTM[0] = m_CTM[3] = 1.0f;
+    m_CTM[1] = m_CTM[2] = 0;
+}
+CPDF_TextStateData::CPDF_TextStateData(const CPDF_TextStateData& src)
+{
+    if (this == &src) {
+        return;
+    }
+    FXSYS_memcpy32(this, &src, sizeof(CPDF_TextStateData));
+    if (m_pDocument && m_pFont) {
+        m_pFont = m_pDocument->GetPageData()->GetFont(m_pFont->GetFontDict(), FALSE);
+    }
+}
+CPDF_TextStateData::~CPDF_TextStateData()
+{
+    if (m_pDocument && m_pFont) {
+        CPDF_DocPageData *pPageData = m_pDocument->GetPageData();
+        if (pPageData && !pPageData->IsForceClear()) {
+            pPageData->ReleaseFont(m_pFont->GetFontDict());
+        }
+    }
+}
+void CPDF_TextState::SetFont(CPDF_Font* pFont)
+{
+    CPDF_TextStateData* pStateData = GetModify();
+    if (pStateData) {
+        CPDF_Document* pDoc = pStateData->m_pDocument;
+        CPDF_DocPageData *pPageData = pDoc ? pDoc->GetPageData() : NULL;
+        if (pPageData && pStateData->m_pFont && !pPageData->IsForceClear()) {
+            pPageData->ReleaseFont(pStateData->m_pFont->GetFontDict());
+        }
+        pStateData->m_pDocument = pFont ? pFont->m_pDocument : NULL;
+        pStateData->m_pFont = pFont;
+    }
+}
+FX_FLOAT CPDF_TextState::GetFontSizeV() const
+{
+    FX_FLOAT* pMatrix = GetMatrix();
+    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[1], pMatrix[3]);
+    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());
+    return (FX_FLOAT)FXSYS_fabs(size);
+}
+FX_FLOAT CPDF_TextState::GetFontSizeH() const
+{
+    FX_FLOAT* pMatrix = GetMatrix();
+    FX_FLOAT unit = FXSYS_sqrt2(pMatrix[0], pMatrix[2]);
+    FX_FLOAT size = FXSYS_Mul(unit, GetFontSize());
+    return (FX_FLOAT)FXSYS_fabs(size);
+}
+FX_FLOAT CPDF_TextState::GetBaselineAngle() const
+{
+    FX_FLOAT* m_Matrix = GetMatrix();
+    return FXSYS_atan2(m_Matrix[2], m_Matrix[0]);
+}
+FX_FLOAT CPDF_TextState::GetShearAngle() const
+{
+    FX_FLOAT* m_Matrix = GetMatrix();
+    FX_FLOAT shear_angle = FXSYS_atan2(m_Matrix[1], m_Matrix[3]);
+    return GetBaselineAngle() + shear_angle;
+}
+CPDF_GeneralStateData::CPDF_GeneralStateData()
+{
+    FXSYS_memset32(this, 0, sizeof(CPDF_GeneralStateData));
+    FXSYS_strcpy((FX_LPSTR)m_BlendMode, (FX_LPCSTR)"Normal");
+    m_StrokeAlpha = 1.0f;
+    m_FillAlpha = 1.0f;
+    m_Flatness = 1.0f;
+    m_Matrix.SetIdentity();
+}
+CPDF_GeneralStateData::CPDF_GeneralStateData(const CPDF_GeneralStateData& src)
+{
+    FXSYS_memcpy32(this, &src, sizeof(CPDF_GeneralStateData));
+    if (src.m_pTransferFunc && src.m_pTransferFunc->m_pPDFDoc) {
+        CPDF_DocRenderData* pDocCache = src.m_pTransferFunc->m_pPDFDoc->GetRenderData();
+        if (!pDocCache) {
+            return;
+        }
+        m_pTransferFunc = pDocCache->GetTransferFunc(m_pTR);
+    }
+}
+CPDF_GeneralStateData::~CPDF_GeneralStateData()
+{
+    if (m_pTransferFunc && m_pTransferFunc->m_pPDFDoc) {
+        CPDF_DocRenderData* pDocCache = m_pTransferFunc->m_pPDFDoc->GetRenderData();
+        if (!pDocCache) {
+            return;
+        }
+        pDocCache->ReleaseTransferFunc(m_pTR);
+    }
+}
+static int GetBlendType(FX_BSTR mode)
+{
+    switch (mode.GetID()) {
+        case FXBSTR_ID('N', 'o', 'r', 'm'):
+        case FXBSTR_ID('C', 'o', 'm', 'p'):
+            return FXDIB_BLEND_NORMAL;
+        case FXBSTR_ID('M', 'u', 'l', 't'):
+            return FXDIB_BLEND_MULTIPLY;
+        case FXBSTR_ID('S', 'c', 'r', 'e'):
+            return FXDIB_BLEND_SCREEN;
+        case FXBSTR_ID('O', 'v', 'e', 'r'):
+            return FXDIB_BLEND_OVERLAY;
+        case FXBSTR_ID('D', 'a', 'r', 'k'):
+            return FXDIB_BLEND_DARKEN;
+        case FXBSTR_ID('L', 'i', 'g', 'h'):
+            return FXDIB_BLEND_LIGHTEN;
+        case FXBSTR_ID('C', 'o', 'l', 'o'):
+            if (mode.GetLength() == 10) {
+                return FXDIB_BLEND_COLORDODGE;
+            }
+            if (mode.GetLength() == 9) {
+                return FXDIB_BLEND_COLORBURN;
+            }
+            return FXDIB_BLEND_COLOR;
+        case FXBSTR_ID('H', 'a', 'r', 'd'):
+            return FXDIB_BLEND_HARDLIGHT;
+        case FXBSTR_ID('S', 'o', 'f', 't'):
+            return FXDIB_BLEND_SOFTLIGHT;
+        case FXBSTR_ID('D', 'i', 'f', 'f'):
+            return FXDIB_BLEND_DIFFERENCE;
+        case FXBSTR_ID('E', 'x', 'c', 'l'):
+            return FXDIB_BLEND_EXCLUSION;
+        case FXBSTR_ID('H', 'u', 'e', 0):
+            return FXDIB_BLEND_HUE;
+        case FXBSTR_ID('S', 'a', 't', 'u'):
+            return FXDIB_BLEND_SATURATION;
+        case FXBSTR_ID('L', 'u', 'm', 'i'):
+            return FXDIB_BLEND_LUMINOSITY;
+    }
+    return FXDIB_BLEND_NORMAL;
+}
+void CPDF_GeneralStateData::SetBlendMode(FX_BSTR blend_mode)
+{
+    if (blend_mode.GetLength() > 15) {
+        return;
+    }
+    FXSYS_memcpy32(m_BlendMode, (FX_LPCBYTE)blend_mode, blend_mode.GetLength());
+    m_BlendMode[blend_mode.GetLength()] = 0;
+    m_BlendType = ::GetBlendType(blend_mode);
+}
+int RI_StringToId(const CFX_ByteString& ri)
+{
+    FX_DWORD id = ri.GetID();
+    if (id == FXBSTR_ID('A', 'b', 's', 'o')) {
+        return 1;
+    }
+    if (id == FXBSTR_ID('S', 'a', 't', 'u')) {
+        return 2;
+    }
+    if (id == FXBSTR_ID('P', 'e', 'r', 'c')) {
+        return 3;
+    }
+    return 0;
+}
+void CPDF_GeneralState::SetRenderIntent(const CFX_ByteString& ri)
+{
+    GetModify()->m_RenderIntent = RI_StringToId(ri);
+}
+CPDF_AllStates::CPDF_AllStates()
+{
+    m_TextX = m_TextY = m_TextLineX = m_TextLineY = 0;
+    m_TextLeading = 0;
+    m_TextRise = 0;
+    m_TextHorzScale = 1.0f;
+}
+CPDF_AllStates::~CPDF_AllStates()
+{
+}
+void CPDF_AllStates::Copy(const CPDF_AllStates& src)
+{
+    CopyStates(src);
+    m_TextMatrix.Copy(src.m_TextMatrix);
+    m_ParentMatrix.Copy(src.m_ParentMatrix);
+    m_CTM.Copy(src.m_CTM);
+    m_TextX = src.m_TextX;
+    m_TextY = src.m_TextY;
+    m_TextLineX = src.m_TextLineX;
+    m_TextLineY = src.m_TextLineY;
+    m_TextLeading = src.m_TextLeading;
+    m_TextRise = src.m_TextRise;
+    m_TextHorzScale = src.m_TextHorzScale;
+}
+void CPDF_AllStates::SetLineDash(CPDF_Array* pArray, FX_FLOAT phase, FX_FLOAT scale)
+{
+    CFX_GraphStateData* pData = m_GraphState.GetModify();
+    pData->m_DashPhase = FXSYS_Mul(phase, scale);
+    pData->SetDashCount(pArray->GetCount());
+    for (FX_DWORD i = 0; i < pArray->GetCount(); i ++) {
+        pData->m_DashArray[i] = FXSYS_Mul(pArray->GetNumber(i), scale);
+    }
+}
+void CPDF_AllStates::ProcessExtGS(CPDF_Dictionary* pGS, CPDF_StreamContentParser* pParser)
+{
+    CPDF_GeneralStateData* pGeneralState = m_GeneralState.GetModify();
+    FX_POSITION pos = pGS->GetStartPos();
+    while (pos) {
+        CFX_ByteString key_str;
+        CPDF_Object* pElement = pGS->GetNextElement(pos, key_str);
+        CPDF_Object* pObject = pElement ? pElement->GetDirect() : NULL;
+        if (pObject == NULL) {
+            continue;
+        }
+        FX_DWORD key = key_str.GetID();
+        switch (key) {
+            case FXBSTR_ID('L', 'W', 0, 0):
+                m_GraphState.GetModify()->m_LineWidth = pObject->GetNumber();
+                break;
+            case FXBSTR_ID('L', 'C', 0, 0):
+                m_GraphState.GetModify()->m_LineCap = (CFX_GraphStateData::LineCap)pObject->GetInteger();
+                break;
+            case FXBSTR_ID('L', 'J', 0, 0):
+                m_GraphState.GetModify()->m_LineJoin = (CFX_GraphStateData::LineJoin)pObject->GetInteger();
+                break;
+            case FXBSTR_ID('M', 'L', 0, 0):
+                m_GraphState.GetModify()->m_MiterLimit = pObject->GetNumber();
+                break;
+            case FXBSTR_ID('D', 0, 0, 0):      {
+                    if (pObject->GetType() != PDFOBJ_ARRAY) {
+                        break;
+                    }
+                    CPDF_Array* pDash = (CPDF_Array*)pObject;
+                    CPDF_Array* pArray = pDash->GetArray(0);
+                    if (pArray == NULL) {
+                        break;
+                    }
+                    SetLineDash(pArray, pDash->GetNumber(1), 1.0f);
+                    break;
+                }
+            case FXBSTR_ID('R', 'I', 0, 0):
+                m_GeneralState.SetRenderIntent(pObject->GetString());
+                break;
+            case FXBSTR_ID('F', 'o', 'n', 't'):        {
+                    if (pObject->GetType() != PDFOBJ_ARRAY) {
+                        break;
+                    }
+                    CPDF_Array* pFont = (CPDF_Array*)pObject;
+                    m_TextState.GetModify()->m_FontSize = pFont->GetNumber(1);
+                    m_TextState.SetFont(pParser->FindFont(pFont->GetString(0)));
+                    break;
+                }
+            case FXBSTR_ID('T', 'R', 0, 0):
+                if (pGS->KeyExist(FX_BSTRC("TR2"))) {
+                    continue;
+                }
+            case FXBSTR_ID('T', 'R', '2', 0):
+                if (pObject && pObject->GetType() != PDFOBJ_NAME) {
+                    pGeneralState->m_pTR = pObject;
+                } else {
+                    pGeneralState->m_pTR = NULL;
+                }
+                break;
+            case FXBSTR_ID('B', 'M', 0, 0):    {
+                    CFX_ByteString mode;
+                    if (pObject->GetType() == PDFOBJ_ARRAY) {
+                        mode = ((CPDF_Array*)pObject)->GetString(0);
+                    } else {
+                        mode = pObject->GetString();
+                    }
+                    pGeneralState->SetBlendMode(mode);
+                    if (pGeneralState->m_BlendType > FXDIB_BLEND_MULTIPLY) {
+                        pParser->m_pObjectList->m_bBackgroundAlphaNeeded = TRUE;
+                    }
+                    break;
+                }
+            case FXBSTR_ID('S', 'M', 'a', 's'):
+                if (pObject && pObject->GetType() == PDFOBJ_DICTIONARY) {
+                    pGeneralState->m_pSoftMask = pObject;
+                    FXSYS_memcpy32(pGeneralState->m_SMaskMatrix, &pParser->m_pCurStates->m_CTM, sizeof(CPDF_Matrix));
+                } else {
+                    pGeneralState->m_pSoftMask = NULL;
+                }
+                break;
+            case FXBSTR_ID('C', 'A', 0, 0):
+                pGeneralState->m_StrokeAlpha = PDF_ClipFloat(pObject->GetNumber());
+                break;
+            case FXBSTR_ID('c', 'a', 0, 0):
+                pGeneralState->m_FillAlpha = PDF_ClipFloat(pObject->GetNumber());
+                break;
+            case FXBSTR_ID('O', 'P', 0, 0):
+                pGeneralState->m_StrokeOP = pObject->GetInteger();
+                if (!pGS->KeyExist(FX_BSTRC("op"))) {
+                    pGeneralState->m_FillOP = pObject->GetInteger();
+                }
+                break;
+            case FXBSTR_ID('o', 'p', 0, 0):
+                pGeneralState->m_FillOP = pObject->GetInteger();
+                break;
+            case FXBSTR_ID('O', 'P', 'M', 0):
+                pGeneralState->m_OPMode = pObject->GetInteger();
+                break;
+            case FXBSTR_ID('B', 'G', 0, 0):
+                if (pGS->KeyExist(FX_BSTRC("BG2"))) {
+                    continue;
+                }
+            case FXBSTR_ID('B', 'G', '2', 0):
+                pGeneralState->m_pBG = pObject;
+                break;
+            case FXBSTR_ID('U', 'C', 'R', 0):
+                if (pGS->KeyExist(FX_BSTRC("UCR2"))) {
+                    continue;
+                }
+            case FXBSTR_ID('U', 'C', 'R', '2'):
+                pGeneralState->m_pUCR = pObject;
+                break;
+            case FXBSTR_ID('H', 'T', 0, 0):
+                pGeneralState->m_pHT = pObject;
+                break;
+            case FXBSTR_ID('F', 'L', 0, 0):
+                pGeneralState->m_Flatness = pObject->GetNumber();
+                break;
+            case FXBSTR_ID('S', 'M', 0, 0):
+                pGeneralState->m_Smoothness = pObject->GetNumber();
+                break;
+            case FXBSTR_ID('S', 'A', 0, 0):
+                pGeneralState->m_StrokeAdjust = pObject->GetInteger();
+                break;
+            case FXBSTR_ID('A', 'I', 'S', 0):
+                pGeneralState->m_AlphaSource = pObject->GetInteger();
+                break;
+            case FXBSTR_ID('T', 'K', 0, 0):
+                pGeneralState->m_TextKnockout = pObject->GetInteger();
+                break;
+        }
+    }
+    pGeneralState->m_Matrix = m_CTM;
+}
+CPDF_ContentMarkItem::CPDF_ContentMarkItem()
+{
+    m_ParamType = None;
+}
+CPDF_ContentMarkItem::CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src)
+{
+    m_MarkName = src.m_MarkName;
+    m_ParamType = src.m_ParamType;
+    if (m_ParamType == DirectDict) {
+        m_pParam = ((CPDF_Dictionary*)src.m_pParam)->Clone();
+    } else {
+        m_pParam = src.m_pParam;
+    }
+}
+CPDF_ContentMarkItem::~CPDF_ContentMarkItem()
+{
+    if (m_ParamType == DirectDict && m_pParam) {
+        ((CPDF_Dictionary*)m_pParam)->Release();
+    }
+}
+FX_BOOL        CPDF_ContentMarkItem::HasMCID() const
+{
+    if (m_pParam && (m_ParamType == DirectDict || m_ParamType == PropertiesDict)) {
+        return ((CPDF_Dictionary *)m_pParam)->KeyExist(FX_BSTRC("MCID"));
+    }
+    return FALSE;
+}
+CPDF_ContentMarkData::CPDF_ContentMarkData(const CPDF_ContentMarkData& src)
+{
+    for (int i = 0; i < src.m_Marks.GetSize(); i ++) {
+        m_Marks.Add(src.m_Marks[i]);
+    }
+}
+int CPDF_ContentMarkData::GetMCID() const
+{
+    CPDF_ContentMarkItem::ParamType type = CPDF_ContentMarkItem::None;
+    for (int i = 0; i < m_Marks.GetSize(); i ++) {
+        type = m_Marks[i].GetParamType();
+        if (type == CPDF_ContentMarkItem::PropertiesDict || type == CPDF_ContentMarkItem::DirectDict) {
+            CPDF_Dictionary *pDict = (CPDF_Dictionary *)m_Marks[i].GetParam();
+            if (pDict->KeyExist(FX_BSTRC("MCID"))) {
+                return pDict->GetInteger(FX_BSTRC("MCID"));
+            }
+        }
+    }
+    return -1;
+}
+void CPDF_ContentMarkData::AddMark(const CFX_ByteString& name, CPDF_Dictionary* pDict, FX_BOOL bDirect)
+{
+    CPDF_ContentMarkItem& item = m_Marks.Add();
+    item.SetName(name);
+    if (pDict == NULL) {
+        return;
+    }
+    item.SetParam(bDirect ? CPDF_ContentMarkItem::DirectDict : CPDF_ContentMarkItem::PropertiesDict,
+                  bDirect ? pDict->Clone() : pDict);
+}
+void CPDF_ContentMarkData::DeleteLastMark()
+{
+    int size = m_Marks.GetSize();
+    if (size == 0) {
+        return;
+    }
+    m_Marks.RemoveAt(size - 1);
+}
+FX_BOOL CPDF_ContentMark::HasMark(FX_BSTR mark) const
+{
+    if (m_pObject == NULL) {
+        return FALSE;
+    }
+    for (int i = 0; i < m_pObject->CountItems(); i ++) {
+        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
+        if (item.GetName() == mark) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+FX_BOOL CPDF_ContentMark::LookupMark(FX_BSTR mark, CPDF_Dictionary*& pDict) const
+{
+    if (m_pObject == NULL) {
+        return FALSE;
+    }
+    for (int i = 0; i < m_pObject->CountItems(); i ++) {
+        CPDF_ContentMarkItem& item = m_pObject->GetItem(i);
+        if (item.GetName() == mark) {
+            pDict = NULL;
+            if (item.GetParamType() == CPDF_ContentMarkItem::PropertiesDict ||
+                    item.GetParamType() == CPDF_ContentMarkItem::DirectDict) {
+                pDict = (CPDF_Dictionary*)item.GetParam();
+            }
+            return TRUE;
+        }
+    }
+    return FALSE;
+}