1e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Copyright 2014 PDFium Authors. All rights reserved.
2e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Use of this source code is governed by a BSD-style license that can be
3e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// found in the LICENSE file.
4e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
5e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
7e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../../include/fxge/fx_ge.h"
8e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../../include/fpdfapi/fpdf_render.h"
9e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../../../include/fpdfapi/fpdf_pageobj.h"
10e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "../fpdf_page/pageint.h"
11e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include "render_int.h"
12e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovextern FX_BOOL IsAvailableMatrix(const CFX_AffineMatrix& matrix);
13e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCPDF_Type3Cache::~CPDF_Type3Cache()
14e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
15e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_POSITION pos = m_SizeMap.GetStartPosition();
16e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_ByteString Key;
17e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Type3Glyphs* pSizeCache = NULL;
18e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    while(pos) {
19e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pSizeCache = (CPDF_Type3Glyphs*)m_SizeMap.GetNextValue(pos);
20e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        delete pSizeCache;
21e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
22e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    m_SizeMap.RemoveAll();
23e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
24e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCFX_GlyphBitmap* CPDF_Type3Cache::LoadGlyph(FX_DWORD charcode, const CFX_AffineMatrix* pMatrix, FX_FLOAT retinaScaleX, FX_FLOAT retinaScaleY)
25e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
26e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    _CPDF_UniqueKeyGen keygen;
27e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    keygen.Generate(4, FXSYS_round(pMatrix->a * 10000), FXSYS_round(pMatrix->b * 10000),
28e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    FXSYS_round(pMatrix->c * 10000), FXSYS_round(pMatrix->d * 10000));
29e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
30e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Type3Glyphs* pSizeCache = NULL;
31e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if(!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
32e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pSizeCache = new CPDF_Type3Glyphs;
33e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
34e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
35e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_GlyphBitmap* pGlyphBitmap;
36e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if(pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)charcode, (void*&)pGlyphBitmap)) {
37e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return pGlyphBitmap;
38e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
39e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pGlyphBitmap = RenderGlyph(pSizeCache, charcode, pMatrix, retinaScaleX, retinaScaleY);
40e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)charcode, pGlyphBitmap);
41e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return pGlyphBitmap;
42e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
43e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCPDF_Type3Glyphs::~CPDF_Type3Glyphs()
44e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
45e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_POSITION pos = m_GlyphMap.GetStartPosition();
46e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_LPVOID Key;
47e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_GlyphBitmap* pGlyphBitmap;
48e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    while(pos) {
49e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
50e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        delete pGlyphBitmap;
51e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
52e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
53e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic int _AdjustBlue(FX_FLOAT pos, int& count, int blues[])
54e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
55e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT min_distance = 1000000.0f * 1.0f;
56e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int closest_pos = -1;
57e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int i = 0; i < count; i ++) {
58e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_FLOAT distance = (FX_FLOAT)FXSYS_fabs(pos - (FX_FLOAT)blues[i]);
59e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (distance < 1.0f * 80.0f / 100.0f && distance < min_distance) {
60e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            min_distance = distance;
61e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            closest_pos = i;
62e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
63e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
64e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (closest_pos >= 0) {
65e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return blues[closest_pos];
66e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
67e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int new_pos = FXSYS_round(pos);
68e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (count == TYPE3_MAX_BLUES) {
69e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return new_pos;
70e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
71e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    blues[count++] = new_pos;
72e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return new_pos;
73e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
74e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid CPDF_Type3Glyphs::AdjustBlue(FX_FLOAT top, FX_FLOAT bottom, int& top_line, int& bottom_line)
75e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
76e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    top_line = _AdjustBlue(top, m_TopBlueCount, m_TopBlue);
77e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    bottom_line = _AdjustBlue(bottom, m_BottomBlueCount, m_BottomBlue);
78e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
79e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic FX_BOOL _IsScanLine1bpp(FX_LPBYTE pBuf, int width)
80e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
81e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int size = width / 8;
82e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int i = 0; i < size; i ++)
83e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pBuf[i]) {
84e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
85e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
86e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (width % 8)
87e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pBuf[width / 8] & (0xff << (8 - width % 8))) {
88e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
89e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
90e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return FALSE;
91e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
92e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic FX_BOOL _IsScanLine8bpp(FX_LPBYTE pBuf, int width)
93e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
94e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int i = 0; i < width; i ++)
95e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pBuf[i] > 0x40) {
96e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
97e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
98e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return FALSE;
99e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
100e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic int _DetectFirstLastScan(const CFX_DIBitmap* pBitmap, FX_BOOL bFirst)
101e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
102e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int height = pBitmap->GetHeight(), pitch = pBitmap->GetPitch(), width = pBitmap->GetWidth();
103e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int bpp = pBitmap->GetBPP();
104e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (bpp > 8) {
105e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        width *= bpp / 8;
106e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
107e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_LPBYTE pBuf = pBitmap->GetBuffer();
108e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int line = bFirst ? 0 : height - 1;
109e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int line_step = bFirst ? 1 : -1;
110e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int line_end = bFirst ? height : -1;
111e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    while (line != line_end) {
112e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (bpp == 1) {
113e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (_IsScanLine1bpp(pBuf + line * pitch, width)) {
114e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                return line;
115e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
116e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else {
117e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (_IsScanLine8bpp(pBuf + line * pitch, width)) {
118e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                return line;
119e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
120e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
121e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        line += line_step;
122e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
123e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return -1;
124e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
125e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCFX_GlyphBitmap* CPDF_Type3Cache::RenderGlyph(CPDF_Type3Glyphs* pSize, FX_DWORD charcode, const CFX_AffineMatrix* pMatrix, FX_FLOAT retinaScaleX, FX_FLOAT retinaScaleY)
126e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
127e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Type3Char* pChar = m_pFont->LoadChar(charcode);
128e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pChar == NULL || pChar->m_pBitmap == NULL) {
129e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return NULL;
130e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
131e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_DIBitmap* pBitmap = pChar->m_pBitmap;
132e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix image_matrix, text_matrix;
133e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    image_matrix = pChar->m_ImageMatrix;
134e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    text_matrix.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d, 0, 0);
135e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    image_matrix.Concat(text_matrix);
136e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_DIBitmap* pResBitmap = NULL;
137e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int left, top;
138e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (FXSYS_fabs(image_matrix.b) < FXSYS_fabs(image_matrix.a) / 100 && FXSYS_fabs(image_matrix.c) < FXSYS_fabs(image_matrix.d) / 100) {
139e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        int top_line, bottom_line;
140e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        top_line = _DetectFirstLastScan(pBitmap, TRUE);
141e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        bottom_line = _DetectFirstLastScan(pBitmap, FALSE);
142e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (top_line == 0 && bottom_line == pBitmap->GetHeight() - 1) {
143e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FX_FLOAT top_y = image_matrix.d + image_matrix.f;
144e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FX_FLOAT bottom_y = image_matrix.f;
145e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FX_BOOL bFlipped = top_y > bottom_y;
146e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (bFlipped) {
147e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                FX_FLOAT temp = top_y;
148e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                top_y = bottom_y;
149e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                bottom_y = temp;
150e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
151e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            pSize->AdjustBlue(top_y, bottom_y, top_line, bottom_line);
152e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            pResBitmap = pBitmap->StretchTo((int)(FXSYS_round(image_matrix.a) * retinaScaleX), (int)((bFlipped ? top_line - bottom_line : bottom_line - top_line) * retinaScaleY));
153e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            top = top_line;
154e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (image_matrix.a < 0) {
155e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                image_matrix.Scale(retinaScaleX, retinaScaleY);
156e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                left = FXSYS_round(image_matrix.e + image_matrix.a);
157e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            } else {
158e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                left = FXSYS_round(image_matrix.e);
159e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
160e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else {
161e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
162e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
163e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pResBitmap == NULL) {
164e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        image_matrix.Scale(retinaScaleX, retinaScaleY);
165e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pResBitmap = pBitmap->TransformTo(&image_matrix, left, top);
166e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
167e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pResBitmap == NULL) {
168e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return NULL;
169e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
170e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_GlyphBitmap* pGlyph = new CFX_GlyphBitmap;
171e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pGlyph->m_Left = left;
172e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pGlyph->m_Top = -top;
173e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pGlyph->m_Bitmap.TakeOver(pResBitmap);
174e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    delete pResBitmap;
175e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return pGlyph;
176e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
177e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid _CPDF_UniqueKeyGen::Generate(int count, ...)
178e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
179e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    va_list argList;
180e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    va_start(argList, count);
181e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int i = 0; i < count; i ++) {
182e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        int p = va_arg(argList, int);
183e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        ((FX_DWORD*)m_Key)[i] = p;
184e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
185e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    va_end(argList);
186e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    m_KeyLen = count * sizeof(FX_DWORD);
187e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
188e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_BOOL CPDF_RenderStatus::ProcessText(const CPDF_TextObject* textobj, const CFX_AffineMatrix* pObj2Device, CFX_PathData* pClippingPath)
189e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
190e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if(textobj->m_nChars == 0) {
191e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return TRUE;
192e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
193e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int text_render_mode = textobj->m_TextState.GetObject()->m_TextMode;
194e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (text_render_mode == 3) {
195e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return TRUE;
196e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
197e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Font* pFont = textobj->m_TextState.GetFont();
198e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->GetFontType() == PDFFONT_TYPE3) {
199e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return ProcessType3Text(textobj, pObj2Device);
200e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
201e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_BOOL bFill = FALSE, bStroke = FALSE, bClip = FALSE;
202e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pClippingPath) {
203e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        bClip = TRUE;
204e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else {
205e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        switch (text_render_mode) {
206e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 0:
207e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 4:
208e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                bFill = TRUE;
209e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                break;
210e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 1:
211e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 5:
212e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
213e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    bFill = TRUE;
214e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                } else {
215e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    bStroke = TRUE;
216e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
217e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                break;
218e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 2:
219e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 6:
220e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
221e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    bFill = TRUE;
222e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                } else {
223e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    bFill = bStroke = TRUE;
224e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
225e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                break;
226e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 3:
227e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            case 7:
228e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                return TRUE;
229e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            default:
230e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                bFill = TRUE;
231e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
232e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
233e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_ARGB stroke_argb = 0, fill_argb = 0;
234e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_BOOL bPattern = FALSE;
235e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (bStroke) {
236e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) {
237e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            bPattern = TRUE;
238e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else {
239e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            stroke_argb = GetStrokeArgb(textobj);
240e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
241e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
242e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (bFill) {
243e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (textobj->m_ColorState.GetFillColor()->IsPattern()) {
244e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            bPattern = TRUE;
245e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else {
246e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            fill_argb = GetFillArgb(textobj);
247e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
248e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
249e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix text_matrix;
250e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    textobj->GetTextMatrix(&text_matrix);
251e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if(IsAvailableMatrix(text_matrix) == FALSE) {
252e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return TRUE;
253e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
254e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
255e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (bPattern) {
256e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size, &text_matrix, bFill, bStroke);
257e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return TRUE;
258e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
259e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (bClip || bStroke) {
260e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        const CFX_AffineMatrix* pDeviceMatrix = pObj2Device;
261e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CFX_AffineMatrix device_matrix;
262e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (bStroke) {
263e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            const FX_FLOAT* pCTM = textobj->m_TextState.GetObject()->m_CTM;
264e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) {
265e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CFX_AffineMatrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0);
266e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                text_matrix.ConcatInverse(ctm);
267e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                device_matrix.Copy(ctm);
268e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                device_matrix.Concat(*pObj2Device);
269e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                pDeviceMatrix = &device_matrix;
270e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
271e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
272e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        int flag = 0;
273e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (bStroke && bFill) {
274e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            flag |= FX_FILL_STROKE;
275e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            flag |= FX_STROKE_TEXT_MODE;
276e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
277e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        const CPDF_GeneralStateData* pGeneralData = ((CPDF_PageObject*)textobj)->m_GeneralState;
278e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pGeneralData && pGeneralData->m_StrokeAdjust) {
279e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            flag |= FX_STROKE_ADJUST;
280e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
281e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (m_Options.m_Flags & RENDER_NOTEXTSMOOTH) {
282e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            flag |= FXFILL_NOPATHSMOOTH;
283e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
284e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return CPDF_TextRenderer::DrawTextPath(m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size,
285e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                               &text_matrix, pDeviceMatrix, textobj->m_GraphState, fill_argb, stroke_argb, pClippingPath, flag);
286e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
287e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    text_matrix.Concat(*pObj2Device);
288e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return CPDF_TextRenderer::DrawNormalText(m_pDevice, textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size,
289e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            &text_matrix, fill_argb, &m_Options);
290e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
291e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCPDF_Type3Cache* CPDF_RenderStatus::GetCachedType3(CPDF_Type3Font* pFont)
292e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
293e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->m_pDocument == NULL) {
294e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return NULL;
295e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
296e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pFont->m_pDocument->GetPageData()->GetFont(pFont->GetFontDict(), FALSE);
297e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return pFont->m_pDocument->GetRenderData()->GetCachedType3(pFont);
298e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
299e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovstatic void ReleaseCachedType3(CPDF_Type3Font* pFont)
300e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
301e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->m_pDocument == NULL) {
302e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return;
303e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
304e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pFont->m_pDocument->GetRenderData()->ReleaseCachedType3(pFont);
305e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pFont->m_pDocument->GetPageData()->ReleaseFont(pFont->GetFontDict());
306e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
307e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_BOOL CPDF_Type3Char::LoadBitmap(CPDF_RenderContext* pContext)
308e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
309e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (m_pBitmap != NULL || m_pForm == NULL) {
310e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return TRUE;
311e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
312e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (m_pForm->CountObjects() == 1 && !m_bColored) {
313e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_PageObject *pPageObj = m_pForm->GetObjectAt(m_pForm->GetFirstObjectPosition());
314e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pPageObj->m_Type == PDFPAGE_IMAGE) {
315e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            CPDF_ImageObject* pImage = (CPDF_ImageObject*)pPageObj;
316e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            m_ImageMatrix = pImage->m_Matrix;
317e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            const CFX_DIBSource* pSource = pImage->m_pImage->LoadDIBSource();
318e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (pSource) {
319e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pBitmap = pSource->Clone();
320e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                delete pSource;
321e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
322e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            delete m_pForm;
323e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            m_pForm = NULL;
324e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
325e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
326e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pPageObj->m_Type == PDFPAGE_INLINES) {
327e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            CPDF_InlineImages *pInlines = (CPDF_InlineImages *)pPageObj;
328e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (pInlines->m_pStream) {
329e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_ImageMatrix = pInlines->m_Matrices[0];
330e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CPDF_DIBSource dibsrc;
331e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (!dibsrc.Load(pContext->m_pDocument, pInlines->m_pStream, NULL, NULL, NULL, NULL)) {
332e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    return FALSE;
333e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
334e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pBitmap = dibsrc.Clone();
335e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                delete m_pForm;
336e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pForm = NULL;
337e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                return TRUE;
338e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
339e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
340e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
341e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return FALSE;
342e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
343e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovclass CPDF_RefType3Cache
344e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
345e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovpublic:
346e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_RefType3Cache(CPDF_Type3Font* pType3Font)
347e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    {
348e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        m_dwCount = 0;
349e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        m_pType3Font = pType3Font;
350e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
351e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    ~CPDF_RefType3Cache()
352e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    {
353e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        while(m_dwCount--) {
354e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            ReleaseCachedType3(m_pType3Font);
355e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
356e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
357e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_DWORD m_dwCount;
358e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Type3Font* m_pType3Font;
359e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov};
360e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_BOOL CPDF_RenderStatus::ProcessType3Text(const CPDF_TextObject* textobj, const CFX_AffineMatrix* pObj2Device)
361e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
362e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->GetType3Font();
363e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int j = 0; j < m_Type3FontCache.GetSize(); j++)
364e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if ((CPDF_Type3Font*)m_Type3FontCache.GetAt(j) == pType3Font) {
365e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
366e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
367e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_Matrix dCTM = m_pDevice->GetCTM();
368e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT sa = FXSYS_fabs(dCTM.a);
369e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT sd = FXSYS_fabs(dCTM.d);
370e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix text_matrix;
371e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    textobj->GetTextMatrix(&text_matrix);
372e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix char_matrix = pType3Font->GetFontMatrix();
373e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT font_size = textobj->m_TextState.GetFontSize();
374e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    char_matrix.Scale(font_size, font_size);
375e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_ARGB fill_argb = GetFillArgb(textobj, TRUE);
376e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int fill_alpha = FXARGB_A(fill_argb);
377e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int device_class = m_pDevice->GetDeviceClass();
378e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FXTEXT_GLYPHPOS* pGlyphAndPos = NULL;
379e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (device_class == FXDC_DISPLAY) {
380e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, textobj->m_nChars);
381e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else if (fill_alpha < 255) {
382e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return FALSE;
383e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
384e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_RefType3Cache refTypeCache(pType3Font);
385e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_DWORD *pChars = textobj->m_pCharCodes;
386e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (textobj->m_nChars == 1) {
387e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pChars = (FX_DWORD*)(&textobj->m_pCharCodes);
388e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
389e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int iChar = 0; iChar < textobj->m_nChars; iChar ++) {
390e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_DWORD charcode = pChars[iChar];
391e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (charcode == (FX_DWORD) - 1) {
392e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            continue;
393e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
394e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode);
395e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pType3Char == NULL) {
396e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            continue;
397e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
398e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CFX_AffineMatrix matrix = char_matrix;
399e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        matrix.e += iChar ? textobj->m_pCharPos[iChar - 1] : 0;
400e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        matrix.Concat(text_matrix);
401e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        matrix.Concat(*pObj2Device);
402e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (!pType3Char->LoadBitmap(m_pContext)) {
403e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (pGlyphAndPos) {
404e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                for (int i = 0; i < iChar; i ++) {
405e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[i];
406e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    if (glyph.m_pGlyph == NULL) {
407e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                        continue;
408e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    }
409e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    m_pDevice->SetBitMask(&glyph.m_pGlyph->m_Bitmap,
410e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                          glyph.m_OriginX + glyph.m_pGlyph->m_Left,
411e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                          glyph.m_OriginY - glyph.m_pGlyph->m_Top, fill_argb);
412e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
413e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                FX_Free(pGlyphAndPos);
414e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                pGlyphAndPos = NULL;
415e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
416e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            CPDF_GraphicStates* pStates = CloneObjStates(textobj, FALSE);
417e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            CPDF_RenderOptions Options = m_Options;
418e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            Options.m_Flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA;
419e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            Options.m_Flags &= ~RENDER_FORCE_DOWNSAMPLE;
420e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            CPDF_Dictionary* pFormResource = NULL;
421e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (pType3Char->m_pForm && pType3Char->m_pForm->m_pFormDict) {
422e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                pFormResource = pType3Char->m_pForm->m_pFormDict->GetDict(FX_BSTRC("Resources"));
423e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
424e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (fill_alpha == 255) {
425e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CPDF_RenderStatus status;
426e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.Initialize(m_pContext, m_pDevice, NULL, NULL, this, pStates, &Options,
427e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                  pType3Char->m_pForm->m_Transparency, m_bDropObjects, pFormResource, FALSE, pType3Char, fill_argb);
428e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.m_Type3FontCache.Append(m_Type3FontCache);
429e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.m_Type3FontCache.Add(pType3Font);
430e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pDevice->SaveState();
431e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.RenderObjectList(pType3Char->m_pForm, &matrix);
432e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pDevice->RestoreState();
433e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            } else {
434e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CFX_FloatRect rect_f = pType3Char->m_pForm->CalcBoundingBox();
435e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                rect_f.Transform(&matrix);
436e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                FX_RECT rect = rect_f.GetOutterRect();
437e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CFX_FxgeDevice bitmap_device;
438e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (!bitmap_device.Create((int)(rect.Width() * sa), (int)(rect.Height() * sd), FXDIB_Argb)) {
439e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    return TRUE;
440e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
441e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                bitmap_device.GetBitmap()->Clear(0);
442e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CPDF_RenderStatus status;
443e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.Initialize(m_pContext, &bitmap_device, NULL, NULL, this, pStates, &Options,
444e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                  pType3Char->m_pForm->m_Transparency, m_bDropObjects, pFormResource, FALSE, pType3Char, fill_argb);
445e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.m_Type3FontCache.Append(m_Type3FontCache);
446e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.m_Type3FontCache.Add(pType3Font);
447e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                matrix.TranslateI(-rect.left, -rect.top);
448e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                matrix.Scale(sa, sd);
449e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                status.RenderObjectList(pType3Char->m_pForm, &matrix);
450e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top);
451e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
452e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            delete pStates;
453e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else if (pType3Char->m_pBitmap) {
454e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (device_class == FXDC_DISPLAY) {
455e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CPDF_Type3Cache* pCache = GetCachedType3(pType3Font);
456e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                refTypeCache.m_dwCount++;
457e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd);
458e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (pBitmap == NULL) {
459e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    continue;
460e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
461e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                int origin_x = FXSYS_round(matrix.e);
462e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                int origin_y = FXSYS_round(matrix.f);
463e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (pGlyphAndPos) {
464e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    pGlyphAndPos[iChar].m_pGlyph = pBitmap;
465e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    pGlyphAndPos[iChar].m_OriginX = origin_x;
466e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    pGlyphAndPos[iChar].m_OriginY = origin_y;
467e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                } else {
468e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    m_pDevice->SetBitMask(&pBitmap->m_Bitmap, origin_x + pBitmap->m_Left, origin_y - pBitmap->m_Top, fill_argb);
469e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
470e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            } else {
471e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CFX_AffineMatrix image_matrix = pType3Char->m_ImageMatrix;
472e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                image_matrix.Concat(matrix);
473e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                CPDF_ImageRenderer renderer;
474e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (renderer.Start(this, pType3Char->m_pBitmap, fill_argb, 255, &image_matrix, 0, FALSE)) {
475e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    renderer.Continue(NULL);
476e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
477e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                if (!renderer.m_Result) {
478e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                    return FALSE;
479e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                }
480e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
481e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
482e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
483e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pGlyphAndPos) {
484e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_RECT rect = FXGE_GetGlyphsBBox(pGlyphAndPos, textobj->m_nChars, 0, sa, sd);
485e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CFX_DIBitmap bitmap;
486e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (!bitmap.Create((int)(rect.Width() * sa), (int)(rect.Height() * sd), FXDIB_8bppMask)) {
487e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FX_Free(pGlyphAndPos);
488e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            return TRUE;
489e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
490e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        bitmap.Clear(0);
491e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        for (int iChar = 0; iChar < textobj->m_nChars; iChar ++) {
492e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
493e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (glyph.m_pGlyph == NULL) {
494e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                continue;
495e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
496e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            bitmap.TransferBitmap((int)((glyph.m_OriginX + glyph.m_pGlyph->m_Left - rect.left) * sa),
497e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                  (int)((glyph.m_OriginY - glyph.m_pGlyph->m_Top - rect.top) * sd),
498e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                  glyph.m_pGlyph->m_Bitmap.GetWidth(), glyph.m_pGlyph->m_Bitmap.GetHeight(),
499e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                  &glyph.m_pGlyph->m_Bitmap, 0, 0);
500e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
501e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        m_pDevice->SetBitMask(&bitmap, rect.left, rect.top, fill_argb);
502e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_Free(pGlyphAndPos);
503e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
504e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return TRUE;
505e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
506e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovclass CPDF_CharPosList
507e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
508e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovpublic:
509e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_CharPosList();
510e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    ~CPDF_CharPosList();
511e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    void				Load(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos, CPDF_Font* pFont, FX_FLOAT font_size);
512e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FXTEXT_CHARPOS*		m_pCharPos;
513e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_DWORD			m_nChars;
514e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov};
515e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_FLOAT _CIDTransformToFloat(FX_BYTE ch);
516e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCPDF_CharPosList::CPDF_CharPosList()
517e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
518e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    m_pCharPos = NULL;
519e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
520e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCPDF_CharPosList::~CPDF_CharPosList()
521e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
522e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (m_pCharPos) {
523e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_Free(m_pCharPos);
524e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
525e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
526e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid CPDF_CharPosList::Load(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos, CPDF_Font* pFont,
527e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                            FX_FLOAT FontSize)
528e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
529e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, nChars);
530e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    m_nChars = 0;
531e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_CIDFont* pCIDFont = pFont->GetCIDFont();
532e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_BOOL bVertWriting = pCIDFont && pCIDFont->IsVertWriting();
533e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (int iChar = 0; iChar < nChars; iChar ++) {
534e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_DWORD CharCode = nChars == 1 ? (FX_DWORD)(FX_UINTPTR)pCharCodes : pCharCodes[iChar];
535e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (CharCode == (FX_DWORD) - 1) {
536e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            continue;
537e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
538e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_BOOL bVert = FALSE;
539e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FXTEXT_CHARPOS& charpos = m_pCharPos[m_nChars++];
540e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pCIDFont) {
541e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_bFontStyle = pCIDFont->IsFontStyleFromCharCode(CharCode);
542e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
543e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charpos.m_GlyphIndex = pFont->GlyphFromCharCode(CharCode, &bVert);
544e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
545e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charpos.m_ExtGID = pFont->GlyphFromCharCodeExt(CharCode);
546e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#endif
547e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (!pFont->IsEmbedded() && pFont->GetFontType() != PDFFONT_CIDFONT) {
548e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_FontCharWidth = pFont->GetCharWidthF(CharCode);
549e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        } else {
550e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_FontCharWidth = 0;
551e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
552e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charpos.m_OriginX = iChar ? pCharPos[iChar - 1] : 0;
553e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charpos.m_OriginY = 0;
554e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charpos.m_bGlyphAdjust = FALSE;
555e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pCIDFont == NULL) {
556e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            continue;
557e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
558e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_WORD CID = pCIDFont->CIDFromCharCode(CharCode);
559e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (bVertWriting) {
560e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginY = charpos.m_OriginX;
561e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginX = 0;
562e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            short vx, vy;
563e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            pCIDFont->GetVertOrigin(CID, vx, vy);
564e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginX -= FontSize * vx / 1000;
565e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginY -= FontSize * vy / 1000;
566e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
567e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_LPCBYTE pTransform = pCIDFont->GetCIDTransform(CID);
568e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pTransform && !bVert) {
569e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_AdjustMatrix[0] = _CIDTransformToFloat(pTransform[0]);
570e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_AdjustMatrix[2] = _CIDTransformToFloat(pTransform[2]);
571e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_AdjustMatrix[1] = _CIDTransformToFloat(pTransform[1]);
572e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_AdjustMatrix[3] = _CIDTransformToFloat(pTransform[3]);
573e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginX += _CIDTransformToFloat(pTransform[4]) * FontSize;
574e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_OriginY += _CIDTransformToFloat(pTransform[5]) * FontSize;
575e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            charpos.m_bGlyphAdjust = TRUE;
576e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
577e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
578e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
579e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_BOOL CPDF_TextRenderer::DrawTextPath(CFX_RenderDevice* pDevice, int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos,
580e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                        CPDF_Font* pFont, FX_FLOAT font_size,
581e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                        const CFX_AffineMatrix* pText2User, const CFX_AffineMatrix* pUser2Device,
582e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                        const CFX_GraphStateData* pGraphState,
583e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                        FX_ARGB fill_argb, FX_ARGB stroke_argb, CFX_PathData* pClippingPath, int nFlag)
584e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
585e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_FontCache* pCache = pFont->m_pDocument ? pFont->m_pDocument->GetRenderData()->GetFontCache() : NULL;
586e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_CharPosList CharPosList;
587e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size);
588e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return pDevice->DrawTextPath(CharPosList.m_nChars, CharPosList.m_pCharPos,
589e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                 &pFont->m_Font, pCache, font_size, pText2User, pUser2Device,
590e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                 pGraphState, fill_argb, stroke_argb, pClippingPath, nFlag);
591e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
592e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice, int left, int top, CPDF_Font* pFont, int height,
593e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                       const CFX_ByteString& str, FX_ARGB argb)
594e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
595e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_RECT font_bbox;
596e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    pFont->GetFontBBox(font_bbox);
597e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT font_size = (FX_FLOAT)height * 1000.0f / (FX_FLOAT)(font_bbox.top - font_bbox.bottom);
598e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT origin_x = (FX_FLOAT)left;
599e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT origin_y = (FX_FLOAT)top + font_size * (FX_FLOAT)font_bbox.top / 1000.0f;
600e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix matrix(1.0f, 0, 0, -1.0f, 0, 0);
601e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    DrawTextString(pDevice, origin_x, origin_y, pFont, font_size, &matrix, str, argb);
602e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
603e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid CPDF_TextRenderer::DrawTextString(CFX_RenderDevice* pDevice, FX_FLOAT origin_x, FX_FLOAT origin_y, CPDF_Font* pFont, FX_FLOAT font_size,
604e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                       const CFX_AffineMatrix* pMatrix, const CFX_ByteString& str, FX_ARGB fill_argb,
605e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                       FX_ARGB stroke_argb, const CFX_GraphStateData* pGraphState, const CPDF_RenderOptions* pOptions)
606e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
607e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int nChars = pFont->CountChar(str, str.GetLength());
608e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (nChars == 0) {
609e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return;
610e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
611e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_DWORD charcode;
612e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int offset = 0;
613e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_DWORD* pCharCodes;
614e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FLOAT* pCharPos;
615e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (nChars == 1) {
616e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        charcode = pFont->GetNextChar(str, str.GetLength(), offset);
617e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCharCodes = (FX_DWORD*)(FX_UINTPTR)charcode;
618e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCharPos = NULL;
619e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else {
620e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCharCodes = FX_Alloc(FX_DWORD, nChars);
621e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCharPos = FX_Alloc(FX_FLOAT, nChars - 1);
622e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_FLOAT cur_pos = 0;
623e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        for (int i = 0; i < nChars; i ++) {
624e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            pCharCodes[i] = pFont->GetNextChar(str, str.GetLength(), offset);
625e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (i) {
626e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                pCharPos[i - 1] = cur_pos;
627e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
628e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            cur_pos += pFont->GetCharWidthF(pCharCodes[i]) * font_size / 1000;
629e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
630e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
631e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_AffineMatrix matrix;
632e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pMatrix) {
633e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        matrix = *pMatrix;
634e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
635e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    matrix.e = origin_x;
636e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    matrix.f = origin_y;
637e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->GetFontType() == PDFFONT_TYPE3)
638e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        ;
639e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    else if (stroke_argb == 0) {
640e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        DrawNormalText(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, &matrix, fill_argb, pOptions);
641e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else
642e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        DrawTextPath(pDevice, nChars, pCharCodes, pCharPos, pFont, font_size, &matrix, NULL, pGraphState,
643e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                     fill_argb, stroke_argb, NULL);
644e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (nChars > 1) {
645e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_Free(pCharCodes);
646e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_Free(pCharPos);
647e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
648e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
649e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovFX_BOOL CPDF_TextRenderer::DrawNormalText(CFX_RenderDevice* pDevice, int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos,
650e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_Font* pFont, FX_FLOAT font_size,
651e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        const CFX_AffineMatrix* pText2Device,
652e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_ARGB fill_argb, const CPDF_RenderOptions* pOptions)
653e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
654e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_FontCache* pCache = pFont->m_pDocument ? pFont->m_pDocument->GetRenderData()->GetFontCache() : NULL;
655e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_CharPosList CharPosList;
656e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CharPosList.Load(nChars, pCharCodes, pCharPos, pFont, font_size);
657e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int FXGE_flags = 0;
658e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pOptions) {
659e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FX_DWORD dwFlags = pOptions->m_Flags;
660e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (dwFlags & RENDER_CLEARTYPE) {
661e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXGE_flags |= FXTEXT_CLEARTYPE;
662e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            if (dwFlags & RENDER_BGR_STRIPE) {
663e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                FXGE_flags |= FXTEXT_BGR_STRIPE;
664e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
665e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
666e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (dwFlags & RENDER_NOTEXTSMOOTH) {
667e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXGE_flags |= FXTEXT_NOSMOOTH;
668e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
669e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (dwFlags & RENDER_PRINTGRAPHICTEXT) {
670e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXGE_flags |= FXTEXT_PRINTGRAPHICTEXT;
671e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
672e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (dwFlags & RENDER_NO_NATIVETEXT) {
673e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXGE_flags |= FXTEXT_NO_NATIVETEXT;
674e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
675e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (dwFlags & RENDER_PRINTIMAGETEXT) {
676e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            FXGE_flags |= FXTEXT_PRINTIMAGETEXT;
677e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
678e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else {
679e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FXGE_flags = FXTEXT_CLEARTYPE;
680e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
681e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->GetFontType() & PDFFONT_CIDFONT) {
682e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FXGE_flags |= FXFONT_CIDFONT;
683e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
684e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return pDevice->DrawNormalText(CharPosList.m_nChars, CharPosList.m_pCharPos, &pFont->m_Font, pCache, font_size, pText2Device, fill_argb, FXGE_flags);
685e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
686e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganovvoid CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj, const CFX_AffineMatrix* pObj2Device,
687e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_Font* pFont, FX_FLOAT font_size,
688e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        const CFX_AffineMatrix* pTextMatrix, FX_BOOL bFill, FX_BOOL bStroke)
689e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
690e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (!bStroke) {
691e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_PathObject path;
692e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_TextObject* pCopy = new CPDF_TextObject;
693e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCopy->Copy(textobj);
694e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_bStroke = FALSE;
695e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_FillType = FXFILL_WINDING;
696e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_ClipPath.AppendTexts(&pCopy, 1);
697e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_ColorState = textobj->m_ColorState;
698e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Path.New()->AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right, textobj->m_Top);
699e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Left = textobj->m_Left;
700e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Bottom = textobj->m_Bottom;
701e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Right = textobj->m_Right;
702e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Top = textobj->m_Top;
703e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        RenderSingleObject(&path, pObj2Device);
704e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return;
705e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
706e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_FontCache* pCache;
707e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (pFont->m_pDocument) {
708e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCache = pFont->m_pDocument->GetRenderData()->GetFontCache();
709e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    } else {
710e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        pCache = CFX_GEModule::Get()->GetFontCache();
711e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
712e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CFX_FaceCache* pFaceCache = pCache->GetCachedFace(&pFont->m_Font);
713e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FX_FONTCACHE_DEFINE(pCache, &pFont->m_Font);
714e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CPDF_CharPosList CharPosList;
715e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    CharPosList.Load(textobj->m_nChars, textobj->m_pCharCodes, textobj->m_pCharPos, pFont, font_size);
716e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    for (FX_DWORD i = 0; i < CharPosList.m_nChars; i ++) {
717e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i];
718e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        const CFX_PathData* pPath = pFaceCache->LoadGlyphPath(&pFont->m_Font, charpos.m_GlyphIndex,
719e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                                    charpos.m_FontCharWidth);
720e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (pPath == NULL) {
721e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            continue;
722e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        }
723e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CPDF_PathObject path;
724e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_GraphState = textobj->m_GraphState;
725e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_ColorState = textobj->m_ColorState;
726e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        CFX_AffineMatrix matrix;
727e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        if (charpos.m_bGlyphAdjust)
728e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
729e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                       charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
730e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY);
731e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Path.New()->Append(pPath, &matrix);
732e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_Matrix = *pTextMatrix;
733e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_bStroke = bStroke;
734e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.m_FillType = bFill ? FXFILL_WINDING : 0;
735e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        path.CalcBoundingBox();
736e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        ProcessPath(&path, pObj2Device);
737e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
738e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
739e6986e1e8d4a57987f47c215490cb080a65ee29aSvet GanovCFX_PathData* CPDF_Font::LoadGlyphPath(FX_DWORD charcode, int dest_width)
740e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov{
741e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    int glyph_index = GlyphFromCharCode(charcode);
742e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if (m_Font.m_Face == NULL) {
743e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        return NULL;
744e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    }
745e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    return m_Font.LoadGlyphPath(glyph_index, dest_width);
746e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov}
747