1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../include/fpdfdoc/fpdf_doc.h"
8#include "../../include/fpdfdoc/fpdf_vt.h"
9#include "pdf_vt.h"
10const FX_BYTE gFontSizeSteps[] = {	4, 6, 8, 9, 10,	12, 14, 18, 20, 25,	30, 35, 40, 45, 50,	55, 60, 70, 80, 90,	100, 110, 120, 130, 144};
11#define PVT_RETURN_LENGTH					1
12#define PVT_DEFAULT_FONTSIZE				18.0f
13#define PVTWORD_SCRIPT_NORMAL				0
14#define PVTWORD_SCRIPT_SUPER				1
15#define PVTWORD_SCRIPT_SUB					2
16#define	PVT_FONTSCALE						0.001f
17#define PVT_PERCENT							0.01f
18#define PVT_HALF							0.5f
19CLine::CLine()
20{
21}
22CLine::~CLine()
23{
24}
25CPVT_WordPlace CLine::GetBeginWordPlace() const
26{
27    return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, -1);
28}
29CPVT_WordPlace CLine::GetEndWordPlace() const
30{
31    return CPVT_WordPlace(LinePlace.nSecIndex, LinePlace.nLineIndex, m_LineInfo.nEndWordIndex);
32}
33CPVT_WordPlace CLine::GetPrevWordPlace(const CPVT_WordPlace & place) const
34{
35    if (place.nWordIndex > m_LineInfo.nEndWordIndex) {
36        return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, m_LineInfo.nEndWordIndex);
37    }
38    return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, place.nWordIndex - 1);
39}
40CPVT_WordPlace CLine::GetNextWordPlace(const CPVT_WordPlace & place) const
41{
42    if (place.nWordIndex < m_LineInfo.nBeginWordIndex) {
43        return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, m_LineInfo.nBeginWordIndex);
44    }
45    return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, place.nWordIndex + 1);
46}
47CSection::CSection(CPDF_VariableText * pVT) : m_pVT(pVT)
48{
49}
50CSection::~CSection()
51{
52    ResetAll();
53}
54void CSection::ResetAll()
55{
56    ResetWordArray();
57    ResetLineArray();
58}
59void CSection::ResetLineArray()
60{
61    m_LineArray.RemoveAll();
62}
63void CSection::ResetWordArray()
64{
65    for (FX_INT32 i = 0, sz = m_WordArray.GetSize(); i < sz; i++) {
66        delete m_WordArray.GetAt(i);
67    }
68    m_WordArray.RemoveAll();
69}
70void CSection::ResetLinePlace()
71{
72    for (FX_INT32 i = 0, sz = m_LineArray.GetSize(); i < sz; i++) {
73        if (CLine * pLine = m_LineArray.GetAt(i)) {
74            pLine->LinePlace = CPVT_WordPlace(SecPlace.nSecIndex, i, -1);
75        }
76    }
77}
78CPVT_WordPlace CSection::AddWord(const CPVT_WordPlace & place, const CPVT_WordInfo & wordinfo)
79{
80    if (CPVT_WordInfo * pWord = FX_NEW CPVT_WordInfo(wordinfo)) {
81        FX_INT32 nWordIndex = FPDF_MAX(FPDF_MIN(place.nWordIndex, this->m_WordArray.GetSize()), 0);
82        if (nWordIndex == m_WordArray.GetSize()) {
83            m_WordArray.Add(pWord);
84        } else {
85            m_WordArray.InsertAt(nWordIndex, pWord);
86        }
87    }
88    return place;
89}
90CPVT_WordPlace CSection::AddLine(const CPVT_LineInfo & lineinfo)
91{
92    return CPVT_WordPlace(SecPlace.nSecIndex, m_LineArray.Add(lineinfo), -1);
93}
94CPVT_FloatRect CSection::Rearrange()
95{
96    ASSERT(m_pVT != NULL);
97    if (m_pVT->m_nCharArray > 0) {
98        return CTypeset(this).CharArray();
99    } else {
100        return CTypeset(this).Typeset();
101    }
102}
103CPVT_Size CSection::GetSectionSize(FX_FLOAT fFontSize)
104{
105    return CTypeset(this).GetEditSize(fFontSize);
106}
107CPVT_WordPlace CSection::GetBeginWordPlace() const
108{
109    if (CLine * pLine = m_LineArray.GetAt(0)) {
110        return pLine->GetBeginWordPlace();
111    } else {
112        return SecPlace;
113    }
114}
115CPVT_WordPlace CSection::GetEndWordPlace() const
116{
117    if (CLine * pLine = m_LineArray.GetAt(m_LineArray.GetSize() - 1)) {
118        return pLine->GetEndWordPlace();
119    } else {
120        return this->SecPlace;
121    }
122}
123CPVT_WordPlace CSection::GetPrevWordPlace(const CPVT_WordPlace & place) const
124{
125    if (place.nLineIndex < 0) {
126        return GetBeginWordPlace();
127    }
128    if (place.nLineIndex >= m_LineArray.GetSize()) {
129        return GetEndWordPlace();
130    }
131    if (CLine * pLine = m_LineArray.GetAt(place.nLineIndex)) {
132        if (place.nWordIndex == pLine->m_LineInfo.nBeginWordIndex) {
133            return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
134        } else if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
135            if (CLine * pPrevLine = m_LineArray.GetAt(place.nLineIndex - 1)) {
136                return pPrevLine->GetEndWordPlace();
137            }
138        } else {
139            return pLine->GetPrevWordPlace(place);
140        }
141    }
142    return place;
143}
144CPVT_WordPlace CSection::GetNextWordPlace(const CPVT_WordPlace & place) const
145{
146    if (place.nLineIndex < 0) {
147        return GetBeginWordPlace();
148    }
149    if (place.nLineIndex >= m_LineArray.GetSize()) {
150        return GetEndWordPlace();
151    }
152    if (CLine * pLine = m_LineArray.GetAt(place.nLineIndex)) {
153        if (place.nWordIndex >= pLine->m_LineInfo.nEndWordIndex) {
154            if (CLine * pNextLine = m_LineArray.GetAt(place.nLineIndex + 1)) {
155                return pNextLine->GetBeginWordPlace();
156            }
157        } else {
158            return pLine->GetNextWordPlace(place);
159        }
160    }
161    return place;
162}
163void CSection::UpdateWordPlace(CPVT_WordPlace & place) const
164{
165    FX_INT32 nLeft = 0;
166    FX_INT32 nRight = m_LineArray.GetSize() - 1;
167    FX_INT32 nMid = (nLeft + nRight) / 2;
168    while (nLeft <= nRight) {
169        if (CLine * pLine = m_LineArray.GetAt(nMid)) {
170            if (place.nWordIndex < pLine->m_LineInfo.nBeginWordIndex) {
171                nRight = nMid - 1;
172                nMid = (nLeft + nRight) / 2;
173            } else if (place.nWordIndex > pLine->m_LineInfo.nEndWordIndex) {
174                nLeft = nMid + 1;
175                nMid = (nLeft + nRight) / 2;
176            } else {
177                place.nLineIndex = nMid;
178                return;
179            }
180        } else {
181            break;
182        }
183    }
184}
185CPVT_WordPlace CSection::SearchWordPlace(const CPDF_Point & point) const
186{
187    ASSERT(m_pVT != NULL);
188    CPVT_WordPlace place = GetBeginWordPlace();
189    FX_BOOL bUp = TRUE;
190    FX_BOOL bDown = TRUE;
191    FX_INT32 nLeft = 0;
192    FX_INT32 nRight = m_LineArray.GetSize() - 1;
193    FX_INT32 nMid = m_LineArray.GetSize() / 2;
194    FX_FLOAT fTop = 0;
195    FX_FLOAT fBottom = 0;
196    while (nLeft <= nRight) {
197        if (CLine * pLine = m_LineArray.GetAt(nMid)) {
198            fTop = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineAscent - m_pVT->GetLineLeading(m_SecInfo);
199            fBottom = pLine->m_LineInfo.fLineY - pLine->m_LineInfo.fLineDescent;
200            if (IsFloatBigger(point.y, fTop)) {
201                bUp = FALSE;
202            }
203            if (IsFloatSmaller(point.y, fBottom)) {
204                bDown = FALSE;
205            }
206            if (IsFloatSmaller(point.y, fTop)) {
207                nRight = nMid - 1;
208                nMid = (nLeft + nRight) / 2;
209                continue;
210            } else if (IsFloatBigger(point.y, fBottom)) {
211                nLeft = nMid + 1;
212                nMid = (nLeft + nRight) / 2;
213                continue;
214            } else {
215                place = SearchWordPlace(point.x,
216                                        CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), pLine->GetEndWordPlace())
217                                       );
218                place.nLineIndex = nMid;
219                return place;
220            }
221        }
222    }
223    if (bUp) {
224        place = GetBeginWordPlace();
225    }
226    if (bDown) {
227        place = GetEndWordPlace();
228    }
229    return place;
230}
231CPVT_WordPlace CSection::SearchWordPlace(FX_FLOAT fx, const CPVT_WordPlace & lineplace) const
232{
233    if (CLine * pLine = m_LineArray.GetAt(lineplace.nLineIndex)) {
234        return SearchWordPlace(fx - m_SecInfo.rcSection.left,
235                               CPVT_WordRange(pLine->GetNextWordPlace(pLine->GetBeginWordPlace()), pLine->GetEndWordPlace()));
236    }
237    return GetBeginWordPlace();
238}
239CPVT_WordPlace CSection::SearchWordPlace(FX_FLOAT fx, const CPVT_WordRange & range) const
240{
241    CPVT_WordPlace wordplace = range.BeginPos;
242    wordplace.nWordIndex = -1;
243    if (!m_pVT)	{
244        return wordplace;
245    }
246    FX_INT32 nLeft = range.BeginPos.nWordIndex;
247    FX_INT32 nRight = range.EndPos.nWordIndex + 1;
248    FX_INT32 nMid = (nLeft + nRight) / 2;
249    while (nLeft < nRight) {
250        if (nMid == nLeft) {
251            break;
252        }
253        if (nMid == nRight) {
254            nMid--;
255            break;
256        }
257        if (CPVT_WordInfo * pWord = m_WordArray.GetAt(nMid)) {
258            if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * PVT_HALF) {
259                nLeft = nMid;
260                nMid = (nLeft + nRight) / 2;
261                continue;
262            } else {
263                nRight = nMid;
264                nMid = (nLeft + nRight) / 2;
265                continue;
266            }
267        } else {
268            break;
269        }
270    }
271    if (CPVT_WordInfo * pWord = m_WordArray.GetAt(nMid)) {
272        if (fx > pWord->fWordX + m_pVT->GetWordWidth(*pWord) * PVT_HALF) {
273            wordplace.nWordIndex = nMid;
274        }
275    }
276    return wordplace;
277}
278void CSection::ClearLeftWords(FX_INT32 nWordIndex)
279{
280    for (FX_INT32 i = nWordIndex; i >= 0; i--) {
281        delete m_WordArray.GetAt(i);
282        m_WordArray.RemoveAt(i);
283    }
284}
285void CSection::ClearRightWords(FX_INT32 nWordIndex)
286{
287    for (FX_INT32 i = m_WordArray.GetSize() - 1; i > nWordIndex; i--) {
288        delete m_WordArray.GetAt(i);
289        m_WordArray.RemoveAt(i);
290    }
291}
292void CSection::ClearMidWords(FX_INT32 nBeginIndex, FX_INT32 nEndIndex)
293{
294    for (FX_INT32 i = nEndIndex; i > nBeginIndex; i--) {
295        delete m_WordArray.GetAt(i);
296        m_WordArray.RemoveAt(i);
297    }
298}
299void CSection::ClearWords(const CPVT_WordRange & PlaceRange)
300{
301    CPVT_WordPlace SecBeginPos = GetBeginWordPlace();
302    CPVT_WordPlace SecEndPos = GetEndWordPlace();
303    if (PlaceRange.BeginPos.WordCmp(SecBeginPos) >= 0) {
304        if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
305            ClearMidWords(PlaceRange.BeginPos.nWordIndex, PlaceRange.EndPos.nWordIndex);
306        } else {
307            ClearRightWords(PlaceRange.BeginPos.nWordIndex);
308        }
309    } else if (PlaceRange.EndPos.WordCmp(SecEndPos) <= 0) {
310        ClearLeftWords(PlaceRange.EndPos.nWordIndex);
311    } else {
312        ResetWordArray();
313    }
314}
315void CSection::ClearWord(const CPVT_WordPlace & place)
316{
317    delete m_WordArray.GetAt(place.nWordIndex);
318    m_WordArray.RemoveAt(place.nWordIndex);
319}
320CTypeset::CTypeset(CSection * pSection) : m_pSection(pSection), m_pVT(pSection->m_pVT), m_rcRet(0.0f, 0.0f, 0.0f, 0.0f)
321{
322}
323CTypeset::~CTypeset()
324{
325}
326CPVT_FloatRect CTypeset::CharArray()
327{
328    ASSERT(m_pSection != NULL);
329    ASSERT(m_pVT != NULL);
330    FX_FLOAT fLineAscent = m_pVT->GetFontAscent(m_pVT->GetDefaultFontIndex(), m_pVT->GetFontSize());
331    FX_FLOAT fLineDescent = m_pVT->GetFontDescent(m_pVT->GetDefaultFontIndex(), m_pVT->GetFontSize());
332    m_rcRet.Default();
333    FX_FLOAT x = 0.0f, y = 0.0f;
334    FX_FLOAT fNextWidth;
335    FX_INT32 nStart = 0;
336    FX_FLOAT fNodeWidth = m_pVT->GetPlateWidth() / (m_pVT->m_nCharArray <= 0 ? 1 : m_pVT->m_nCharArray);
337    if (CLine * pLine = m_pSection->m_LineArray.GetAt(0)) {
338        x = 0.0f;
339        y +=  m_pVT->GetLineLeading(m_pSection->m_SecInfo);
340        y += fLineAscent;
341        nStart = 0;
342        switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) {
343            case 0:
344                pLine->m_LineInfo.fLineX = fNodeWidth * PVT_HALF;
345                break;
346            case 1:
347                nStart = (m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize()) / 2;
348                pLine->m_LineInfo.fLineX = fNodeWidth * nStart - fNodeWidth * PVT_HALF;
349                break;
350            case 2:
351                nStart = m_pVT->m_nCharArray - m_pSection->m_WordArray.GetSize();
352                pLine->m_LineInfo.fLineX = fNodeWidth * nStart - fNodeWidth * PVT_HALF;
353                break;
354        }
355        for (FX_INT32 w = 0, sz = m_pSection->m_WordArray.GetSize(); w < sz; w++) {
356            if (w >= m_pVT->m_nCharArray) {
357                break;
358            }
359            fNextWidth = 0;
360            if (CPVT_WordInfo * pNextWord = (CPVT_WordInfo *)m_pSection->m_WordArray.GetAt(w + 1)) {
361                pNextWord->fWordTail = 0;
362                fNextWidth = m_pVT->GetWordWidth(*pNextWord);
363            }
364            if (CPVT_WordInfo * pWord = (CPVT_WordInfo *)m_pSection->m_WordArray.GetAt(w)) {
365                pWord->fWordTail = 0;
366                FX_FLOAT fWordWidth = m_pVT->GetWordWidth(*pWord);
367                FX_FLOAT fWordAscent = m_pVT->GetWordAscent(*pWord);
368                FX_FLOAT fWordDescent = m_pVT->GetWordDescent(*pWord);
369                x = (FX_FLOAT)(fNodeWidth * (w + nStart + 0.5) - fWordWidth * PVT_HALF);
370                pWord->fWordX = x;
371                pWord->fWordY = y;
372                if (w == 0) {
373                    pLine->m_LineInfo.fLineX = x;
374                }
375                if (w != m_pSection->m_WordArray.GetSize() - 1)
376                    pWord->fWordTail = (fNodeWidth - (fWordWidth + fNextWidth) * PVT_HALF > 0 ?
377                                        fNodeWidth - (fWordWidth + fNextWidth) * PVT_HALF : 0);
378                else {
379                    pWord->fWordTail = 0;
380                }
381                x += fWordWidth;
382                fLineAscent = FPDF_MAX(fLineAscent, fWordAscent);
383                fLineDescent = FPDF_MIN(fLineDescent, fWordDescent);
384            }
385        }
386        pLine->m_LineInfo.nBeginWordIndex = 0;
387        pLine->m_LineInfo.nEndWordIndex = m_pSection->m_WordArray.GetSize() - 1;
388        pLine->m_LineInfo.fLineY = y;
389        pLine->m_LineInfo.fLineWidth = 	x - pLine->m_LineInfo.fLineX;
390        pLine->m_LineInfo.fLineAscent = fLineAscent;
391        pLine->m_LineInfo.fLineDescent = fLineDescent;
392        y += (-fLineDescent);
393    }
394    return m_rcRet = CPVT_FloatRect(0, 0, x, y);
395}
396CPVT_Size CTypeset::GetEditSize(FX_FLOAT fFontSize)
397{
398    ASSERT(m_pSection != NULL);
399    ASSERT(m_pVT != NULL);
400    SplitLines(FALSE, fFontSize);
401    return CPVT_Size(m_rcRet.Width(), m_rcRet.Height());
402}
403CPVT_FloatRect CTypeset::Typeset()
404{
405    ASSERT(m_pSection != NULL);
406    ASSERT(m_pVT != NULL);
407    m_pSection->m_LineArray.Empty();
408    SplitLines(TRUE, 0.0f);
409    m_pSection->m_LineArray.Clear();
410    OutputLines();
411    return m_rcRet;
412}
413static int special_chars[128] = {
414    0x0000, 0x000C, 0x0008, 0x000C, 0x0008, 0x0000, 0x0020, 0x0000,
415    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
416    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
417    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
418    0x0000, 0x0008, 0x0008, 0x0000, 0x0010, 0x0000, 0x0000, 0x0028,
419    0x000C, 0x0008, 0x0000, 0x0000, 0x0028, 0x0028, 0x0028, 0x0028,
420    0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
421    0x0002, 0x0002, 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0008,
422    0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
423    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
424    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
425    0x0001, 0x0001, 0x0001, 0x000C, 0x0000, 0x0008, 0x0000, 0x0000,
426    0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
427    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
428    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
429    0x0001, 0x0001, 0x0001, 0x000C, 0x0000, 0x0008, 0x0000, 0x0000,
430};
431static FX_BOOL IsLatin(FX_WORD word)
432{
433    if (word <= 0x007F) {
434        if (special_chars[word] & 0x0001) {
435            return TRUE;
436        }
437    }
438    if ((word >= 0x00C0 && word <= 0x00FF) ||
439            (word >= 0x0100 && word <= 0x024F) ||
440            (word >= 0x1E00 && word <= 0x1EFF) ||
441            (word >= 0x2C60 && word <= 0x2C7F) ||
442            (word >= 0xA720 && word <= 0xA7FF) ||
443            (word >= 0xFF21 && word <= 0xFF3A) ||
444            (word >= 0xFF41 && word <= 0xFF5A)) {
445        return TRUE;
446    }
447    return FALSE;
448}
449static FX_BOOL IsDigit(FX_DWORD word)
450{
451    return (word >= 0x0030 && word <= 0x0039) ? TRUE : FALSE;
452}
453static FX_BOOL IsCJK(FX_DWORD word)
454{
455    if ((word >= 0x1100 && word <= 0x11FF) ||
456            (word >= 0x2E80 && word <= 0x2FFF) ||
457            (word >= 0x3040 && word <= 0x9FBF) ||
458            (word >= 0xAC00 && word <= 0xD7AF) ||
459            (word >= 0xF900 && word <= 0xFAFF) ||
460            (word >= 0xFE30 && word <= 0xFE4F) ||
461            (word >= 0x20000 && word <= 0x2A6DF) ||
462            (word >= 0x2F800 && word <= 0x2FA1F)) {
463        return TRUE;
464    }
465    if (word >= 0x3000 && word <= 0x303F) {
466        if (word == 0x3005 || word == 0x3006 || word == 0x3021 || word == 0x3022 ||
467                word == 0x3023 || word == 0x3024 || word == 0x3025 || word == 0x3026 ||
468                word == 0x3027 || word == 0x3028 || word == 0x3029 || word == 0x3031 ||
469                word == 0x3032 || word == 0x3033 || word == 0x3034 || word == 0x3035) {
470            return TRUE;
471        }
472        return FALSE;
473    }
474    if (word >= 0xFF66 && word <= 0xFF9D) {
475        return TRUE;
476    }
477    return FALSE;
478}
479static FX_BOOL IsPunctuation(FX_DWORD word)
480{
481    if (word <= 0x007F) {
482        if ((special_chars[word] >> 3) & 1) {
483            return TRUE;
484        }
485    } else if (word >= 0x0080 && word <= 0x00FF) {
486        if (word == 0x0082 || word == 0x0084 || word == 0x0085 || word == 0x0091 ||
487                word == 0x0092 || word == 0x0093 || word <= 0x0094 || word == 0x0096 ||
488                word == 0x00B4 || word == 0x00B8) {
489            return TRUE;
490        }
491    } else if (word >= 0x2000 && word <= 0x206F) {
492        if (word == 0x2010 || word == 0x2011 || word == 0x2012 || word == 0x2013 ||
493                word == 0x2018 || word == 0x2019 || word == 0x201A || word == 0x201B ||
494                word == 0x201C || word == 0x201D || word == 0x201E || word == 0x201F ||
495                word == 0x2032 || word == 0x2033 || word == 0x2034 || word == 0x2035 ||
496                word == 0x2036 || word == 0x2037 || word == 0x203C || word == 0x203D ||
497                word == 0x203E || word == 0x2044) {
498            return TRUE;
499        }
500    } else if (word >= 0x3000 && word <= 0x303F) {
501        if (word == 0x3001 || word == 0x3002 || word == 0x3003 || word == 0x3005 ||
502                word == 0x3009 || word == 0x300A || word == 0x300B || word == 0x300C ||
503                word == 0x300D || word == 0x300F || word == 0x300E || word == 0x3010 ||
504                word == 0x3011 || word == 0x3014 || word == 0x3015 || word == 0x3016 ||
505                word == 0x3017 || word == 0x3018 || word == 0x3019 || word == 0x301A ||
506                word == 0x301B || word == 0x301D || word == 0x301E || word == 0x301F) {
507            return TRUE;
508        }
509    } else if (word >= 0xFE50 && word <= 0xFE6F) {
510        if ((word >= 0xFE50 && word <= 0xFE5E) || word == 0xFE63) {
511            return TRUE;
512        }
513    } else if (word >= 0xFF00 && word <= 0xFFEF) {
514        if (word == 0xFF01 || word == 0xFF02 || word == 0xFF07 || word == 0xFF08 ||
515                word == 0xFF09 || word == 0xFF0C || word == 0xFF0E || word == 0xFF0F ||
516                word == 0xFF1A || word == 0xFF1B || word == 0xFF1F || word == 0xFF3B ||
517                word == 0xFF3D || word == 0xFF40 || word == 0xFF5B || word == 0xFF5C ||
518                word == 0xFF5D || word == 0xFF61 || word == 0xFF62 || word == 0xFF63 ||
519                word == 0xFF64 || word == 0xFF65 || word == 0xFF9E || word == 0xFF9F) {
520            return TRUE;
521        }
522    }
523    return FALSE;
524}
525static FX_BOOL IsConnectiveSymbol(FX_DWORD word)
526{
527    if (word <= 0x007F) {
528        if ((special_chars[word] >> 5) & 1) {
529            return TRUE;
530        }
531    }
532    return FALSE;
533}
534static FX_BOOL IsOpenStylePunctuation(FX_DWORD word)
535{
536    if (word <= 0x007F) {
537        if ((special_chars[word] >> 2) & 1) {
538            return TRUE;
539        }
540    } else if (word == 0x300A || word == 0x300C || word == 0x300E || word == 0x3010 ||
541               word == 0x3014 || word == 0x3016 || word == 0x3018 || word == 0x301A ||
542               word == 0xFF08 || word == 0xFF3B || word == 0xFF5B || word == 0xFF62) {
543        return TRUE;
544    }
545    return FALSE;
546}
547static FX_BOOL IsCurrencySymbol(FX_WORD word)
548{
549    if (word == 0x0024 || word == 0x0080 || word == 0x00A2 || word == 0x00A3 ||
550            word == 0x00A4 || word == 0x00A5 || (word >= 0x20A0 && word <= 0x20CF) ||
551            word == 0xFE69 || word == 0xFF04 || word == 0xFFE0 || word == 0xFFE1 ||
552            word == 0xFFE5 || word == 0xFFE6) {
553        return TRUE;
554    }
555    return FALSE;
556}
557static FX_BOOL IsPrefixSymbol(FX_WORD word)
558{
559    if (IsCurrencySymbol(word)) {
560        return TRUE;
561    }
562    if (word == 0x2116) {
563        return TRUE;
564    }
565    return FALSE;
566}
567static FX_BOOL IsSpace(FX_WORD word)
568{
569    return (word == 0x0020 || word == 0x3000) ? TRUE : FALSE;
570}
571static FX_BOOL NeedDivision(FX_WORD prevWord, FX_WORD curWord)
572{
573    if ((IsLatin(prevWord) || IsDigit(prevWord)) && (IsLatin(curWord) || IsDigit(curWord))) {
574        return FALSE;
575    } else if (IsSpace(curWord) || IsPunctuation(curWord)) {
576        return FALSE;
577    } else if (IsConnectiveSymbol(prevWord) || IsConnectiveSymbol(curWord)) {
578        return FALSE;
579    } else if (IsSpace(prevWord) || IsPunctuation(prevWord)) {
580        return TRUE;
581    } else if (IsPrefixSymbol(prevWord)) {
582        return FALSE;
583    } else if (IsPrefixSymbol(curWord) || IsCJK(curWord)) {
584        return TRUE;
585    } else if (IsCJK(prevWord)) {
586        return TRUE;
587    }
588    return FALSE;
589}
590void CTypeset::SplitLines(FX_BOOL bTypeset, FX_FLOAT fFontSize)
591{
592    ASSERT(m_pVT != NULL);
593    ASSERT(m_pSection != NULL);
594    FX_INT32 nLineHead = 0;
595    FX_INT32 nLineTail = 0;
596    FX_FLOAT fMaxX = 0.0f, fMaxY = 0.0f;
597    FX_FLOAT fLineWidth = 0.0f, fBackupLineWidth = 0.0f;
598    FX_FLOAT fLineAscent = 0.0f, fBackupLineAscent = 0.0f;
599    FX_FLOAT fLineDescent = 0.0f, fBackupLineDescent = 0.0f;
600    FX_INT32 nWordStartPos = 0;
601    FX_BOOL bFullWord = FALSE;
602    FX_INT32 nLineFullWordIndex = 0;
603    FX_INT32 nCharIndex = 0;
604    CPVT_LineInfo line;
605    FX_FLOAT fWordWidth = 0;
606    FX_FLOAT fTypesetWidth = FPDF_MAX(m_pVT->GetPlateWidth() - m_pVT->GetLineIndent(m_pSection->m_SecInfo), 0.0f);
607    FX_INT32 nTotalWords = m_pSection->m_WordArray.GetSize();
608    FX_BOOL bOpened = FALSE;
609    if (nTotalWords > 0) {
610        FX_INT32 i = 0;
611        while (i < nTotalWords) {
612            CPVT_WordInfo * pWord = m_pSection->m_WordArray.GetAt(i);
613            CPVT_WordInfo* pOldWord = pWord;
614            if (i > 0) {
615                pOldWord = m_pSection->m_WordArray.GetAt(i - 1);
616            }
617            if (pWord) {
618                if (bTypeset) {
619                    fLineAscent = FPDF_MAX(fLineAscent, m_pVT->GetWordAscent(*pWord, TRUE));
620                    fLineDescent = FPDF_MIN(fLineDescent, m_pVT->GetWordDescent(*pWord, TRUE));
621                    fWordWidth = m_pVT->GetWordWidth(*pWord);
622                } else {
623                    fLineAscent = FPDF_MAX(fLineAscent, m_pVT->GetWordAscent(*pWord, fFontSize));
624                    fLineDescent = FPDF_MIN(fLineDescent, m_pVT->GetWordDescent(*pWord, fFontSize));
625                    fWordWidth = m_pVT->GetWordWidth(pWord->nFontIndex,
626                                                     pWord->Word,
627                                                     m_pVT->m_wSubWord,
628                                                     m_pVT->m_fCharSpace,
629                                                     m_pVT->m_nHorzScale,
630                                                     fFontSize,
631                                                     pWord->fWordTail,
632                                                     0);
633                }
634                if (!bOpened) {
635                    if (IsOpenStylePunctuation(pWord->Word)) {
636                        bOpened = TRUE;
637                        bFullWord = TRUE;
638                    } else if (pOldWord != NULL) {
639                        if (NeedDivision(pOldWord->Word, pWord->Word)) {
640                            bFullWord = TRUE;
641                        }
642                    }
643                } else {
644                    if (!IsSpace(pWord->Word) && !IsOpenStylePunctuation(pWord->Word)) {
645                        bOpened = FALSE;
646                    }
647                }
648                if (bFullWord) {
649                    bFullWord = FALSE;
650                    if (nCharIndex > 0) {
651                        nLineFullWordIndex ++;
652                    }
653                    nWordStartPos = i;
654                    fBackupLineWidth = fLineWidth;
655                    fBackupLineAscent = fLineAscent;
656                    fBackupLineDescent = fLineDescent;
657                }
658                nCharIndex++;
659            }
660            if (m_pVT->m_bLimitWidth && fTypesetWidth > 0 &&
661                    fLineWidth + fWordWidth > fTypesetWidth) {
662                if (nLineFullWordIndex > 0) {
663                    i = nWordStartPos;
664                    fLineWidth = fBackupLineWidth;
665                    fLineAscent = fBackupLineAscent;
666                    fLineDescent = fBackupLineDescent;
667                }
668                if (nCharIndex == 1) {
669                    fLineWidth =  fWordWidth;
670                    i++;
671                }
672                nLineTail = i - 1;
673                if (bTypeset) {
674                    line.nBeginWordIndex = nLineHead;
675                    line.nEndWordIndex = nLineTail;
676                    line.nTotalWord = nLineTail - nLineHead + 1;
677                    line.fLineWidth = fLineWidth;
678                    line.fLineAscent = fLineAscent;
679                    line.fLineDescent = fLineDescent;
680                    m_pSection->AddLine(line);
681                }
682                fMaxY += (fLineAscent + m_pVT->GetLineLeading(m_pSection->m_SecInfo));
683                fMaxY += (-fLineDescent);
684                fMaxX = FPDF_MAX(fLineWidth, fMaxX);
685                nLineHead = i;
686                fLineWidth = 0.0f;
687                fLineAscent = 0.0f;
688                fLineDescent = 0.0f;
689                nCharIndex = 0;
690                nLineFullWordIndex = 0;
691                bFullWord = FALSE;
692            } else {
693                fLineWidth += fWordWidth;
694                i++;
695            }
696        }
697        if (nLineHead <= nTotalWords - 1) {
698            nLineTail = nTotalWords - 1;
699            if (bTypeset) {
700                line.nBeginWordIndex = nLineHead;
701                line.nEndWordIndex = nLineTail;
702                line.nTotalWord = nLineTail - nLineHead + 1;
703                line.fLineWidth = fLineWidth;
704                line.fLineAscent = fLineAscent;
705                line.fLineDescent = fLineDescent;
706                m_pSection->AddLine(line);
707            }
708            fMaxY += (fLineAscent + m_pVT->GetLineLeading(m_pSection->m_SecInfo));
709            fMaxY += (-fLineDescent);
710            fMaxX = FPDF_MAX(fLineWidth, fMaxX);
711        }
712    } else {
713        if (bTypeset) {
714            fLineAscent = m_pVT->GetLineAscent(m_pSection->m_SecInfo);
715            fLineDescent = m_pVT->GetLineDescent(m_pSection->m_SecInfo);
716        } else {
717            fLineAscent = m_pVT->GetFontAscent(m_pVT->GetDefaultFontIndex(), fFontSize);
718            fLineDescent = m_pVT->GetFontDescent(m_pVT->GetDefaultFontIndex(), fFontSize);
719        }
720        if (bTypeset) {
721            line.nBeginWordIndex = -1;
722            line.nEndWordIndex = -1;
723            line.nTotalWord = 0;
724            line.fLineWidth = 0;
725            line.fLineAscent = fLineAscent;
726            line.fLineDescent = fLineDescent;
727            m_pSection->AddLine(line);
728        }
729        fMaxY += (m_pVT->GetLineLeading(m_pSection->m_SecInfo) + fLineAscent + (-fLineDescent));
730    }
731    m_rcRet = CPVT_FloatRect(0, 0, fMaxX, fMaxY);
732}
733void CTypeset::OutputLines()
734{
735    ASSERT(m_pVT != NULL);
736    ASSERT(m_pSection != NULL);
737    FX_FLOAT fMinX = 0.0f, fMinY = 0.0f, fMaxX = 0.0f, fMaxY = 0.0f;
738    FX_FLOAT fPosX = 0.0f, fPosY = 0.0f;
739    FX_FLOAT fLineIndent = m_pVT->GetLineIndent(m_pSection->m_SecInfo);
740    FX_FLOAT fTypesetWidth = FPDF_MAX(m_pVT->GetPlateWidth() - fLineIndent, 0.0f);
741    switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) {
742        default:
743        case 0:
744            fMinX = 0.0f;
745            break;
746        case 1:
747            fMinX = (fTypesetWidth - m_rcRet.Width())  * PVT_HALF;
748            break;
749        case 2:
750            fMinX = fTypesetWidth - m_rcRet.Width();
751            break;
752    }
753    fMaxX = fMinX + m_rcRet.Width();
754    fMinY = 0.0f;
755    fMaxY = m_rcRet.Height();
756    FX_INT32 nTotalLines = m_pSection->m_LineArray.GetSize();
757    if (nTotalLines > 0) {
758        m_pSection->m_SecInfo.nTotalLine = nTotalLines;
759        for (FX_INT32 l = 0; l < nTotalLines; l++) {
760            if (CLine * pLine = m_pSection->m_LineArray.GetAt(l)) {
761                switch (m_pVT->GetAlignment(m_pSection->m_SecInfo)) {
762                    default:
763                    case 0:
764                        fPosX = 0;
765                        break;
766                    case 1:
767                        fPosX = (fTypesetWidth - pLine->m_LineInfo.fLineWidth) * PVT_HALF;
768                        break;
769                    case 2:
770                        fPosX = fTypesetWidth - pLine->m_LineInfo.fLineWidth;
771                        break;
772                }
773                fPosX += fLineIndent;
774                fPosY += m_pVT->GetLineLeading(m_pSection->m_SecInfo);
775                fPosY += pLine->m_LineInfo.fLineAscent;
776                pLine->m_LineInfo.fLineX = fPosX - fMinX;
777                pLine->m_LineInfo.fLineY = fPosY - fMinY;
778                for (FX_INT32 w = pLine->m_LineInfo.nBeginWordIndex; w <= pLine->m_LineInfo.nEndWordIndex; w++) {
779                    if (CPVT_WordInfo * pWord = m_pSection->m_WordArray.GetAt(w)) {
780                        pWord->fWordX = fPosX - fMinX;
781                        if (pWord->pWordProps) {
782                            switch (pWord->pWordProps->nScriptType) {
783                                default:
784                                case PVTWORD_SCRIPT_NORMAL:
785                                    pWord->fWordY = fPosY - fMinY;
786                                    break;
787                                case PVTWORD_SCRIPT_SUPER:
788                                    pWord->fWordY = fPosY - m_pVT->GetWordAscent(*pWord) - fMinY;
789                                    break;
790                                case PVTWORD_SCRIPT_SUB:
791                                    pWord->fWordY = fPosY - m_pVT->GetWordDescent(*pWord) - fMinY;
792                                    break;
793                            }
794                        } else {
795                            pWord->fWordY = fPosY - fMinY;
796                        }
797                        fPosX += m_pVT->GetWordWidth(*pWord);
798                    }
799                }
800                fPosY += (-pLine->m_LineInfo.fLineDescent);
801            }
802        }
803    }
804    m_rcRet = CPVT_FloatRect(fMinX, fMinY, fMaxX, fMaxY);
805}
806CPDF_VariableText::CPDF_VariableText() :
807    m_pVTProvider(NULL),
808    m_pVTIterator(NULL),
809    m_bInitial(FALSE),
810    m_bRichText(FALSE),
811    m_bMultiLine(FALSE),
812    m_bLimitWidth(FALSE),
813    m_bAutoFontSize(FALSE),
814    m_nLimitChar(0),
815    m_nCharArray(0),
816    m_nAlignment(0),
817    m_fCharSpace(0.0f),
818    m_fWordSpace(0.0f),
819    m_fFontSize(0.0f),
820    m_nHorzScale(100),
821    m_wSubWord(0),
822    m_fLineLeading(0.0f)
823{
824}
825CPDF_VariableText::~CPDF_VariableText()
826{
827    if (m_pVTIterator) {
828        delete m_pVTIterator;
829        m_pVTIterator = NULL;
830    }
831    ResetAll();
832}
833void CPDF_VariableText::Initialize()
834{
835    if (!m_bInitial) {
836        CPVT_SectionInfo secinfo;
837        if (m_bRichText) {
838            secinfo.pSecProps = FX_NEW CPVT_SecProps(0.0f, 0.0f, 0);
839            secinfo.pWordProps = FX_NEW CPVT_WordProps(GetDefaultFontIndex(), PVT_DEFAULT_FONTSIZE, 0, 0, 0);
840        }
841        CPVT_WordPlace place;
842        place.nSecIndex = 0;
843        AddSection(place, secinfo);
844        CPVT_LineInfo lineinfo;
845        lineinfo.fLineAscent = GetFontAscent(GetDefaultFontIndex(), GetFontSize());
846        lineinfo.fLineDescent = GetFontDescent(GetDefaultFontIndex(), GetFontSize());
847        AddLine(place, lineinfo);
848        if (CSection * pSection = m_SectionArray.GetAt(0)) {
849            pSection->ResetLinePlace();
850        }
851        m_bInitial = TRUE;
852    }
853}
854void CPDF_VariableText::ResetAll()
855{
856    m_bInitial = FALSE;
857    ResetSectionArray();
858}
859CPVT_WordPlace CPDF_VariableText::InsertWord(const CPVT_WordPlace & place, FX_WORD word, FX_INT32 charset,
860        const CPVT_WordProps * pWordProps)
861{
862    FX_INT32 nTotlaWords = this->GetTotalWords();
863    if (m_nLimitChar > 0 && nTotlaWords >= m_nLimitChar) {
864        return place;
865    }
866    if (m_nCharArray > 0 && nTotlaWords >= m_nCharArray) {
867        return place;
868    }
869    CPVT_WordPlace newplace = place;
870    newplace.nWordIndex ++;
871    if (m_bRichText) {
872        CPVT_WordProps * pNewProps = pWordProps ? FX_NEW CPVT_WordProps(*pWordProps) : FX_NEW CPVT_WordProps();
873        if (pNewProps) {
874            pNewProps->nFontIndex = GetWordFontIndex(word, charset, pWordProps->nFontIndex);
875            return AddWord(newplace, CPVT_WordInfo(word, charset, -1, pNewProps));
876        }
877    } else {
878        FX_INT32 nFontIndex = GetSubWord() > 0 ? GetDefaultFontIndex() : GetWordFontIndex(word, charset, GetDefaultFontIndex());
879        return AddWord(newplace, CPVT_WordInfo(word, charset, nFontIndex, NULL));
880    }
881    return place;
882}
883CPVT_WordPlace CPDF_VariableText::InsertSection(const CPVT_WordPlace & place, const CPVT_SecProps * pSecProps,
884        const CPVT_WordProps * pWordProps)
885{
886    FX_INT32 nTotlaWords = this->GetTotalWords();
887    if (m_nLimitChar > 0 && nTotlaWords >= m_nLimitChar) {
888        return place;
889    }
890    if (m_nCharArray > 0 && nTotlaWords >= m_nCharArray) {
891        return place;
892    }
893    if (!m_bMultiLine) {
894        return place;
895    }
896    CPVT_WordPlace wordplace = place;
897    UpdateWordPlace(wordplace);
898    CPVT_WordPlace newplace = place;
899    if (CSection * pSection = m_SectionArray.GetAt(wordplace.nSecIndex)) {
900        CPVT_WordPlace NewPlace(wordplace.nSecIndex + 1, 0, -1);
901        CPVT_SectionInfo secinfo;
902        if (m_bRichText) {
903            if (pSecProps) {
904                secinfo.pSecProps = FX_NEW CPVT_SecProps(*pSecProps);
905            }
906            if (pWordProps) {
907                secinfo.pWordProps = FX_NEW CPVT_WordProps(*pWordProps);
908            }
909        }
910        AddSection(NewPlace, secinfo);
911        newplace = NewPlace;
912        if (CSection * pNewSection = m_SectionArray.GetAt(NewPlace.nSecIndex)) {
913            for (FX_INT32 w = wordplace.nWordIndex + 1, sz = pSection->m_WordArray.GetSize(); w < sz; w++) {
914                if (CPVT_WordInfo * pWord = pSection->m_WordArray.GetAt(w)) {
915                    NewPlace.nWordIndex++;
916                    pNewSection->AddWord(NewPlace, *pWord);
917                }
918            }
919        }
920        ClearSectionRightWords(wordplace);
921    }
922    return newplace;
923}
924CPVT_WordPlace CPDF_VariableText::InsertText(const CPVT_WordPlace & place, FX_LPCWSTR text, FX_INT32 charset,
925        const CPVT_SecProps * pSecProps, const CPVT_WordProps * pProps)
926{
927    CFX_WideString swText = text;
928    CPVT_WordPlace wp = place;
929    for (FX_INT32 i = 0, sz = swText.GetLength(); i < sz; i++) {
930        CPVT_WordPlace oldwp = wp;
931        FX_WORD word = swText.GetAt(i);
932        switch (word) {
933            case 0x0D:
934                if (m_bMultiLine) {
935                    if (swText.GetAt(i + 1) == 0x0A) {
936                        i += 1;
937                    }
938                    wp = InsertSection(wp, pSecProps, pProps);
939                }
940                break;
941            case 0x0A:
942                if (m_bMultiLine) {
943                    if (swText.GetAt(i + 1) == 0x0D) {
944                        i += 1;
945                    }
946                    wp = InsertSection(wp, pSecProps, pProps);
947                }
948                break;
949            case 0x09:
950                word = 0x20;
951            default:
952                wp = InsertWord(wp, word, charset, pProps);
953                break;
954        }
955        if (wp == oldwp) {
956            break;
957        }
958    }
959    return wp;
960}
961CPVT_WordPlace CPDF_VariableText::DeleteWords(const CPVT_WordRange & PlaceRange)
962{
963    FX_BOOL bLastSecPos = FALSE;
964    if (CSection * pSection = m_SectionArray.GetAt(PlaceRange.EndPos.nSecIndex)) {
965        bLastSecPos = (PlaceRange.EndPos == pSection->GetEndWordPlace());
966    }
967    ClearWords(PlaceRange);
968    if (PlaceRange.BeginPos.nSecIndex != PlaceRange.EndPos.nSecIndex) {
969        ClearEmptySections(PlaceRange);
970        if (!bLastSecPos) {
971            LinkLatterSection(PlaceRange.BeginPos);
972        }
973    }
974    return PlaceRange.BeginPos;
975}
976CPVT_WordPlace CPDF_VariableText::DeleteWord(const CPVT_WordPlace & place)
977{
978    return ClearRightWord(AjustLineHeader(place, TRUE));
979}
980CPVT_WordPlace CPDF_VariableText::BackSpaceWord(const CPVT_WordPlace & place)
981{
982    return ClearLeftWord(AjustLineHeader(place, TRUE));
983}
984void CPDF_VariableText::SetText(FX_LPCWSTR text, FX_INT32 charset, const CPVT_SecProps * pSecProps,
985                                const CPVT_WordProps * pWordProps)
986{
987    DeleteWords(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
988    CFX_WideString swText = text;
989    CPVT_WordPlace	wp(0, 0, -1);
990    CPVT_SectionInfo secinfo;
991    if (m_bRichText) {
992        if (pSecProps) {
993            secinfo.pSecProps = FX_NEW CPVT_SecProps(*pSecProps);
994        }
995        if (pWordProps) {
996            secinfo.pWordProps = FX_NEW CPVT_WordProps(*pWordProps);
997        }
998    }
999    if (CSection * pSection = m_SectionArray.GetAt(0)) {
1000        pSection->m_SecInfo = secinfo;
1001    }
1002    FX_INT32 nCharCount = 0;
1003    for (FX_INT32 i = 0, sz = swText.GetLength(); i < sz; i++) {
1004        if (m_nLimitChar > 0 && nCharCount >= m_nLimitChar) {
1005            break;
1006        }
1007        if (m_nCharArray > 0 && nCharCount >= m_nCharArray) {
1008            break;
1009        }
1010        FX_WORD word = swText.GetAt(i);
1011        switch (word) {
1012            case 0x0D:
1013                if (m_bMultiLine) {
1014                    if (swText.GetAt(i + 1) == 0x0A) {
1015                        i += 1;
1016                    }
1017                    wp.nSecIndex ++;
1018                    wp.nLineIndex = 0;
1019                    wp.nWordIndex = -1;
1020                    AddSection(wp, secinfo);
1021                }
1022                break;
1023            case 0x0A:
1024                if (m_bMultiLine) {
1025                    if (swText.GetAt(i + 1) == 0x0D) {
1026                        i += 1;
1027                    }
1028                    wp.nSecIndex ++;
1029                    wp.nLineIndex = 0;
1030                    wp.nWordIndex = -1;
1031                    AddSection(wp, secinfo);
1032                }
1033                break;
1034            case 0x09:
1035                word = 0x20;
1036            default:
1037                wp = InsertWord(wp, word, charset, pWordProps);
1038                break;
1039        }
1040        nCharCount++;
1041    }
1042}
1043void CPDF_VariableText::UpdateWordPlace(CPVT_WordPlace & place) const
1044{
1045    if (place.nSecIndex < 0) {
1046        place = GetBeginWordPlace();
1047    }
1048    if (place.nSecIndex >= m_SectionArray.GetSize()) {
1049        place = GetEndWordPlace();
1050    }
1051    place = AjustLineHeader(place, TRUE);
1052    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1053        pSection->UpdateWordPlace(place);
1054    }
1055}
1056FX_INT32 CPDF_VariableText::WordPlaceToWordIndex(const CPVT_WordPlace & place) const
1057{
1058    CPVT_WordPlace newplace = place;
1059    UpdateWordPlace(newplace);
1060    FX_INT32 nIndex = 0;
1061    FX_INT32 i = 0;
1062    FX_INT32 sz = 0;
1063    for (i = 0, sz = m_SectionArray.GetSize(); i < sz && i < newplace.nSecIndex; i++) {
1064        if (CSection * pSection = m_SectionArray.GetAt(i)) {
1065            nIndex += pSection->m_WordArray.GetSize();
1066            if (i != m_SectionArray.GetSize() - 1) {
1067                nIndex += PVT_RETURN_LENGTH;
1068            }
1069        }
1070    }
1071    if (i >= 0 && i < m_SectionArray.GetSize()) {
1072        nIndex += newplace.nWordIndex + PVT_RETURN_LENGTH;
1073    }
1074    return nIndex;
1075}
1076CPVT_WordPlace CPDF_VariableText::WordIndexToWordPlace(FX_INT32 index) const
1077{
1078    CPVT_WordPlace place = GetBeginWordPlace();
1079    FX_INT32 nOldIndex = 0 , nIndex = 0;
1080    FX_BOOL bFind = FALSE;
1081    for (FX_INT32 i = 0, sz = m_SectionArray.GetSize(); i < sz; i++) {
1082        if (CSection * pSection = m_SectionArray.GetAt(i)) {
1083            nIndex += pSection->m_WordArray.GetSize();
1084            if (nIndex == index) {
1085                place = pSection->GetEndWordPlace();
1086                bFind = TRUE;
1087                break;
1088            } else if (nIndex > index) {
1089                place.nSecIndex = i;
1090                place.nWordIndex = index - nOldIndex - 1;
1091                pSection->UpdateWordPlace(place);
1092                bFind = TRUE;
1093                break;
1094            }
1095            if (i != m_SectionArray.GetSize() - 1) {
1096                nIndex += PVT_RETURN_LENGTH;
1097            }
1098            nOldIndex = nIndex;
1099        }
1100    }
1101    if (!bFind) {
1102        place = GetEndWordPlace();
1103    }
1104    return place;
1105}
1106CPVT_WordPlace CPDF_VariableText::GetBeginWordPlace() const
1107{
1108    return m_bInitial ? CPVT_WordPlace(0, 0, -1) : CPVT_WordPlace();
1109}
1110CPVT_WordPlace CPDF_VariableText::GetEndWordPlace() const
1111{
1112    if (CSection * pSection = m_SectionArray.GetAt(m_SectionArray.GetSize() - 1)) {
1113        return pSection->GetEndWordPlace();
1114    }
1115    return CPVT_WordPlace();
1116}
1117CPVT_WordPlace CPDF_VariableText::GetPrevWordPlace(const CPVT_WordPlace & place) const
1118{
1119    if( place.nSecIndex < 0) {
1120        return GetBeginWordPlace();
1121    }
1122    if (place.nSecIndex >= m_SectionArray.GetSize()) {
1123        return GetEndWordPlace();
1124    }
1125    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1126        if (place.WordCmp(pSection->GetBeginWordPlace()) <= 0) {
1127            if (CSection * pPrevSection = m_SectionArray.GetAt(place.nSecIndex - 1)) {
1128                return pPrevSection->GetEndWordPlace();
1129            } else {
1130                return GetBeginWordPlace();
1131            }
1132        } else {
1133            return pSection->GetPrevWordPlace(place);
1134        }
1135    }
1136    return place;
1137}
1138CPVT_WordPlace CPDF_VariableText::GetNextWordPlace(const CPVT_WordPlace & place) const
1139{
1140    if (place.nSecIndex < 0) {
1141        return GetBeginWordPlace();
1142    }
1143    if (place.nSecIndex >= m_SectionArray.GetSize()) {
1144        return GetEndWordPlace();
1145    }
1146    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1147        if (place.WordCmp(pSection->GetEndWordPlace()) >= 0) {
1148            if (CSection * pNextSection = m_SectionArray.GetAt(place.nSecIndex + 1)) {
1149                return pNextSection->GetBeginWordPlace();
1150            } else {
1151                return GetEndWordPlace();
1152            }
1153        } else {
1154            return pSection->GetNextWordPlace(place);
1155        }
1156    }
1157    return place;
1158}
1159CPVT_WordPlace CPDF_VariableText::SearchWordPlace(const CPDF_Point & point) const
1160{
1161    CPDF_Point pt = OutToIn(point);
1162    CPVT_WordPlace place = GetBeginWordPlace();
1163    FX_INT32 nLeft = 0;
1164    FX_INT32 nRight = m_SectionArray.GetSize() - 1;
1165    FX_INT32 nMid = m_SectionArray.GetSize() / 2;
1166    FX_BOOL bUp = TRUE;
1167    FX_BOOL bDown = TRUE;
1168    while (nLeft <= nRight) {
1169        if (CSection * pSection = m_SectionArray.GetAt(nMid)) {
1170            if (IsFloatBigger(pt.y, pSection->m_SecInfo.rcSection.top)) {
1171                bUp = FALSE;
1172            }
1173            if (IsFloatBigger(pSection->m_SecInfo.rcSection.bottom, pt.y)) {
1174                bDown = FALSE;
1175            }
1176            if (IsFloatSmaller(pt.y, pSection->m_SecInfo.rcSection.top)) {
1177                nRight = nMid - 1;
1178                nMid = (nLeft + nRight) / 2;
1179                continue;
1180            } else if (IsFloatBigger(pt.y, pSection->m_SecInfo.rcSection.bottom)) {
1181                nLeft = nMid + 1;
1182                nMid = (nLeft + nRight) / 2;
1183                continue;
1184            } else {
1185                place = pSection->SearchWordPlace(
1186                            CPDF_Point(pt.x - pSection->m_SecInfo.rcSection.left, pt.y - pSection->m_SecInfo.rcSection.top)
1187                        );
1188                place.nSecIndex = nMid;
1189                return place;
1190            }
1191        } else {
1192            break;
1193        }
1194    }
1195    if (bUp) {
1196        place = GetBeginWordPlace();
1197    }
1198    if (bDown) {
1199        place = GetEndWordPlace();
1200    }
1201    return place;
1202}
1203CPVT_WordPlace CPDF_VariableText::GetUpWordPlace(const CPVT_WordPlace & place, const CPDF_Point & point) const
1204{
1205    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1206        CPVT_WordPlace temp =  place;
1207        CPDF_Point pt = OutToIn(point);
1208        if (temp.nLineIndex-- > 0) {
1209            return pSection->SearchWordPlace(pt.x - pSection->m_SecInfo.rcSection.left, temp);
1210        } else {
1211            if (temp.nSecIndex-- > 0) {
1212                if (CSection * pLastSection = m_SectionArray.GetAt(temp.nSecIndex)) {
1213                    temp.nLineIndex = pLastSection->m_LineArray.GetSize() - 1;
1214                    return pLastSection->SearchWordPlace(pt.x - pLastSection->m_SecInfo.rcSection.left, temp);
1215                }
1216            }
1217        }
1218    }
1219    return place;
1220}
1221CPVT_WordPlace CPDF_VariableText::GetDownWordPlace(const CPVT_WordPlace & place, const CPDF_Point & point) const
1222{
1223    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1224        CPVT_WordPlace temp =  place;
1225        CPDF_Point pt = OutToIn(point);
1226        if (temp.nLineIndex++ < pSection->m_LineArray.GetSize() - 1) {
1227            return pSection->SearchWordPlace(pt.x - pSection->m_SecInfo.rcSection.left, temp);
1228        } else {
1229            if (temp.nSecIndex++ < m_SectionArray.GetSize() - 1) {
1230                if (CSection * pNextSection = m_SectionArray.GetAt(temp.nSecIndex)) {
1231                    temp.nLineIndex = 0;
1232                    return pNextSection->SearchWordPlace(pt.x - pSection->m_SecInfo.rcSection.left, temp);
1233                }
1234            }
1235        }
1236    }
1237    return place;
1238}
1239CPVT_WordPlace CPDF_VariableText::GetLineBeginPlace(const CPVT_WordPlace & place) const
1240{
1241    return CPVT_WordPlace(place.nSecIndex, place.nLineIndex, -1);
1242}
1243CPVT_WordPlace CPDF_VariableText::GetLineEndPlace(const CPVT_WordPlace & place) const
1244{
1245    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex))
1246        if (CLine * pLine = pSection->m_LineArray.GetAt(place.nLineIndex)) {
1247            return pLine->GetEndWordPlace();
1248        }
1249    return place;
1250}
1251CPVT_WordPlace CPDF_VariableText::GetSectionBeginPlace(const CPVT_WordPlace & place) const
1252{
1253    return CPVT_WordPlace(place.nSecIndex, 0, -1);
1254}
1255CPVT_WordPlace CPDF_VariableText::GetSectionEndPlace(const CPVT_WordPlace & place) const
1256{
1257    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1258        return pSection->GetEndWordPlace();
1259    }
1260    return place;
1261}
1262FX_INT32 CPDF_VariableText::GetTotalWords() const
1263{
1264    FX_INT32 nTotal = 0;
1265    for (FX_INT32 i = 0, sz = m_SectionArray.GetSize(); i < sz; i++)
1266        if (CSection * pSection = m_SectionArray.GetAt(i)) {
1267            nTotal += (pSection->m_WordArray.GetSize() + PVT_RETURN_LENGTH);
1268        }
1269    return nTotal - PVT_RETURN_LENGTH;
1270}
1271void CPDF_VariableText::ResetSectionArray()
1272{
1273    for (FX_INT32 s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) {
1274        delete m_SectionArray.GetAt(s);
1275    }
1276    m_SectionArray.RemoveAll();
1277}
1278CPVT_WordPlace CPDF_VariableText::AddSection(const CPVT_WordPlace & place, const CPVT_SectionInfo & secinfo)
1279{
1280    if (IsValid() && !m_bMultiLine) {
1281        return place;
1282    }
1283    FX_INT32 nSecIndex = FPDF_MAX(FPDF_MIN(place.nSecIndex, m_SectionArray.GetSize()), 0);
1284    CSection * pSection = FX_NEW CSection(this);
1285    if (!pSection) {
1286        return place;
1287    }
1288    pSection->m_SecInfo = secinfo;
1289    pSection->SecPlace.nSecIndex = nSecIndex;
1290    if (nSecIndex == m_SectionArray.GetSize()) {
1291        m_SectionArray.Add(pSection);
1292    } else {
1293        m_SectionArray.InsertAt(nSecIndex, pSection);
1294    }
1295    return place;
1296}
1297CPVT_WordPlace CPDF_VariableText::AddLine(const CPVT_WordPlace & place, const CPVT_LineInfo & lineinfo)
1298{
1299    if (m_SectionArray.IsEmpty()) {
1300        return place;
1301    }
1302    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1303        return pSection->AddLine(lineinfo);
1304    }
1305    return place;
1306}
1307CPVT_WordPlace CPDF_VariableText::AddWord(const CPVT_WordPlace & place, const CPVT_WordInfo & wordinfo)
1308{
1309    if (m_SectionArray.GetSize() <= 0) {
1310        return place;
1311    }
1312    CPVT_WordPlace newplace = place;
1313    newplace.nSecIndex = FPDF_MAX(FPDF_MIN(newplace.nSecIndex, m_SectionArray.GetSize() - 1), 0);
1314    if (CSection * pSection = m_SectionArray.GetAt(newplace.nSecIndex)) {
1315        return pSection->AddWord(newplace, wordinfo);
1316    }
1317    return place;
1318}
1319FX_BOOL CPDF_VariableText::GetWordInfo(const CPVT_WordPlace & place, CPVT_WordInfo & wordinfo)
1320{
1321    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1322        if (CPVT_WordInfo * pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) {
1323            wordinfo = *pWord;
1324            return TRUE;
1325        }
1326    }
1327    return FALSE;
1328}
1329FX_BOOL CPDF_VariableText::SetWordInfo(const CPVT_WordPlace & place, const CPVT_WordInfo & wordinfo)
1330{
1331    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1332        if (CPVT_WordInfo * pWord = pSection->m_WordArray.GetAt(place.nWordIndex)) {
1333            *pWord = wordinfo;
1334            return TRUE;
1335        }
1336    }
1337    return FALSE;
1338}
1339FX_BOOL CPDF_VariableText::GetLineInfo(const CPVT_WordPlace & place, CPVT_LineInfo & lineinfo)
1340{
1341    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1342        if (CLine * pLine = pSection->m_LineArray.GetAt(place.nLineIndex)) {
1343            lineinfo = pLine->m_LineInfo;
1344            return TRUE;
1345        }
1346    }
1347    return FALSE;
1348}
1349FX_BOOL CPDF_VariableText::GetSectionInfo(const CPVT_WordPlace & place, CPVT_SectionInfo & secinfo)
1350{
1351    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1352        secinfo = pSection->m_SecInfo;
1353        return TRUE;
1354    }
1355    return FALSE;
1356}
1357CPDF_Rect CPDF_VariableText::GetContentRect() const
1358{
1359    return InToOut(CPDF_EditContainer::GetContentRect());
1360}
1361FX_FLOAT CPDF_VariableText::GetWordFontSize(const CPVT_WordInfo & WordInfo, FX_BOOL bFactFontSize)
1362{
1363    return m_bRichText && WordInfo.pWordProps ? (WordInfo.pWordProps->nScriptType == PVTWORD_SCRIPT_NORMAL || bFactFontSize ? WordInfo.pWordProps->fFontSize : WordInfo.pWordProps->fFontSize * PVT_HALF) : GetFontSize();
1364}
1365FX_INT32 CPDF_VariableText::GetWordFontIndex(const CPVT_WordInfo & WordInfo)
1366{
1367    return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->nFontIndex : WordInfo.nFontIndex;
1368}
1369FX_FLOAT CPDF_VariableText::GetWordWidth(FX_INT32 nFontIndex, FX_WORD Word, FX_WORD SubWord,
1370        FX_FLOAT fCharSpace, FX_INT32 nHorzScale,
1371        FX_FLOAT fFontSize, FX_FLOAT fWordTail, FX_INT32 nWordStyle)
1372{
1373    return (GetCharWidth(nFontIndex, Word, SubWord, nWordStyle) * fFontSize * PVT_FONTSCALE + fCharSpace) * nHorzScale * PVT_PERCENT + fWordTail;
1374}
1375FX_FLOAT CPDF_VariableText::GetWordWidth(const CPVT_WordInfo & WordInfo)
1376{
1377    return GetWordWidth(GetWordFontIndex(WordInfo), WordInfo.Word, GetSubWord(), GetCharSpace(WordInfo), GetHorzScale(WordInfo),
1378                        GetWordFontSize(WordInfo), WordInfo.fWordTail,
1379                        WordInfo.pWordProps ? WordInfo.pWordProps->nWordStyle : 0);
1380}
1381FX_FLOAT CPDF_VariableText::GetLineAscent(const CPVT_SectionInfo & SecInfo)
1382{
1383    return m_bRichText && SecInfo.pWordProps ? GetFontAscent(SecInfo.pWordProps->nFontIndex, SecInfo.pWordProps->fFontSize) :
1384           GetFontAscent(GetDefaultFontIndex(), GetFontSize());
1385}
1386FX_FLOAT CPDF_VariableText::GetLineDescent(const CPVT_SectionInfo & SecInfo)
1387{
1388    return m_bRichText && SecInfo.pWordProps ? GetFontDescent(SecInfo.pWordProps->nFontIndex, SecInfo.pWordProps->fFontSize) :
1389           GetFontDescent(GetDefaultFontIndex(), GetFontSize());
1390}
1391FX_FLOAT CPDF_VariableText::GetFontAscent(FX_INT32 nFontIndex, FX_FLOAT fFontSize)
1392{
1393    return (FX_FLOAT)GetTypeAscent(nFontIndex) * fFontSize * PVT_FONTSCALE;
1394}
1395FX_FLOAT CPDF_VariableText::GetFontDescent(FX_INT32 nFontIndex, FX_FLOAT fFontSize)
1396{
1397    return (FX_FLOAT)GetTypeDescent(nFontIndex) * fFontSize * PVT_FONTSCALE;
1398}
1399FX_FLOAT CPDF_VariableText::GetWordAscent(const CPVT_WordInfo & WordInfo, FX_FLOAT fFontSize)
1400{
1401    return GetFontAscent(GetWordFontIndex(WordInfo), fFontSize);
1402}
1403FX_FLOAT CPDF_VariableText::GetWordDescent(const CPVT_WordInfo & WordInfo, FX_FLOAT fFontSize)
1404{
1405    return GetFontDescent(GetWordFontIndex(WordInfo), fFontSize);
1406}
1407FX_FLOAT CPDF_VariableText::GetWordAscent(const CPVT_WordInfo & WordInfo, FX_BOOL bFactFontSize)
1408{
1409    return GetFontAscent(GetWordFontIndex(WordInfo), GetWordFontSize(WordInfo, bFactFontSize));
1410}
1411FX_FLOAT CPDF_VariableText::GetWordDescent(const CPVT_WordInfo & WordInfo, FX_BOOL bFactFontSize)
1412{
1413    return GetFontDescent(GetWordFontIndex(WordInfo), GetWordFontSize(WordInfo, bFactFontSize));
1414}
1415FX_FLOAT CPDF_VariableText::GetLineLeading(const CPVT_SectionInfo & SecInfo)
1416{
1417    return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->fLineLeading : m_fLineLeading;
1418}
1419FX_FLOAT CPDF_VariableText::GetLineIndent(const CPVT_SectionInfo & SecInfo)
1420{
1421    return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->fLineIndent : 0.0f;
1422}
1423FX_INT32 CPDF_VariableText::GetAlignment(const CPVT_SectionInfo& SecInfo)
1424{
1425    return m_bRichText && SecInfo.pSecProps ? SecInfo.pSecProps->nAlignment : this->m_nAlignment;
1426}
1427FX_FLOAT CPDF_VariableText::GetCharSpace(const CPVT_WordInfo & WordInfo)
1428{
1429    return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->fCharSpace : m_fCharSpace;
1430}
1431FX_INT32 CPDF_VariableText::GetHorzScale(const CPVT_WordInfo & WordInfo)
1432{
1433    return m_bRichText && WordInfo.pWordProps ? WordInfo.pWordProps->nHorzScale : m_nHorzScale;
1434}
1435void CPDF_VariableText::ClearSectionRightWords(const CPVT_WordPlace & place)
1436{
1437    CPVT_WordPlace wordplace = AjustLineHeader(place, TRUE);
1438    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1439        for (FX_INT32 w = pSection->m_WordArray.GetSize() - 1; w > wordplace.nWordIndex; w--) {
1440            delete pSection->m_WordArray.GetAt(w);
1441            pSection->m_WordArray.RemoveAt(w);
1442        }
1443    }
1444}
1445CPVT_WordPlace CPDF_VariableText::AjustLineHeader(const CPVT_WordPlace & place, FX_BOOL bPrevOrNext) const
1446{
1447    if (place.nWordIndex < 0 && place.nLineIndex > 0) {
1448        if (bPrevOrNext) {
1449            return GetPrevWordPlace(place);
1450        } else {
1451            return GetNextWordPlace(place);
1452        }
1453    }
1454    return place;
1455}
1456FX_BOOL CPDF_VariableText::ClearEmptySection(const CPVT_WordPlace & place)
1457{
1458    if (place.nSecIndex == 0 && m_SectionArray.GetSize() == 1) {
1459        return FALSE;
1460    }
1461    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1462        if (pSection->m_WordArray.GetSize() == 0) {
1463            delete pSection;
1464            m_SectionArray.RemoveAt(place.nSecIndex);
1465            return TRUE;
1466        }
1467    }
1468    return FALSE;
1469}
1470void CPDF_VariableText::ClearEmptySections(const CPVT_WordRange & PlaceRange)
1471{
1472    CPVT_WordPlace wordplace;
1473    for (FX_INT32 s = PlaceRange.EndPos.nSecIndex; s > PlaceRange.BeginPos.nSecIndex; s--) {
1474        wordplace.nSecIndex = s;
1475        ClearEmptySection(wordplace);
1476    }
1477}
1478void CPDF_VariableText::LinkLatterSection(const CPVT_WordPlace & place)
1479{
1480    CPVT_WordPlace oldplace = AjustLineHeader(place, TRUE);
1481    if (CSection * pNextSection = m_SectionArray.GetAt(place.nSecIndex + 1)) {
1482        if (CSection * pSection = m_SectionArray.GetAt(oldplace.nSecIndex)) {
1483            for (FX_INT32 w = 0, sz = pNextSection->m_WordArray.GetSize(); w < sz; w++) {
1484                if (CPVT_WordInfo * pWord = pNextSection->m_WordArray.GetAt(w)) {
1485                    oldplace.nWordIndex ++;
1486                    pSection->AddWord(oldplace, *pWord);
1487                }
1488            }
1489        }
1490        delete pNextSection;
1491        m_SectionArray.RemoveAt(place.nSecIndex + 1);
1492    }
1493}
1494void CPDF_VariableText::ClearWords(const CPVT_WordRange & PlaceRange)
1495{
1496    CPVT_WordRange NewRange;
1497    NewRange.BeginPos = AjustLineHeader(PlaceRange.BeginPos, TRUE);
1498    NewRange.EndPos = AjustLineHeader(PlaceRange.EndPos, TRUE);
1499    for (FX_INT32 s = NewRange.EndPos.nSecIndex; s >= NewRange.BeginPos.nSecIndex; s--) {
1500        if (CSection * pSection = m_SectionArray.GetAt(s)) {
1501            pSection->ClearWords(NewRange);
1502        }
1503    }
1504}
1505CPVT_WordPlace CPDF_VariableText::ClearLeftWord(const CPVT_WordPlace & place)
1506{
1507    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1508        CPVT_WordPlace leftplace = this->GetPrevWordPlace(place);
1509        if (leftplace != place) {
1510            if (leftplace.nSecIndex != place.nSecIndex) {
1511                if (pSection->m_WordArray.GetSize() == 0) {
1512                    this->ClearEmptySection(place);
1513                } else {
1514                    this->LinkLatterSection(leftplace);
1515                }
1516            } else {
1517                pSection->ClearWord(place);
1518            }
1519        }
1520        return leftplace;
1521    }
1522    return place;
1523}
1524CPVT_WordPlace CPDF_VariableText::ClearRightWord(const CPVT_WordPlace & place)
1525{
1526    if (CSection * pSection = m_SectionArray.GetAt(place.nSecIndex)) {
1527        CPVT_WordPlace rightplace = AjustLineHeader(this->GetNextWordPlace(place), FALSE);
1528        if (rightplace != place) {
1529            if(rightplace.nSecIndex != place.nSecIndex) {
1530                LinkLatterSection(place);
1531            } else {
1532                pSection->ClearWord(rightplace);
1533            }
1534        }
1535    }
1536    return place;
1537}
1538void CPDF_VariableText::RearrangeAll()
1539{
1540    Rearrange(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
1541}
1542void CPDF_VariableText::RearrangePart(const CPVT_WordRange & PlaceRange)
1543{
1544    Rearrange(PlaceRange);
1545}
1546CPVT_FloatRect CPDF_VariableText::Rearrange(const CPVT_WordRange & PlaceRange)
1547{
1548    CPVT_FloatRect rcRet;
1549    if (IsValid()) {
1550        if (m_bAutoFontSize) {
1551            SetFontSize(GetAutoFontSize());
1552            rcRet = RearrangeSections(CPVT_WordRange(GetBeginWordPlace(), GetEndWordPlace()));
1553        } else {
1554            rcRet = RearrangeSections(PlaceRange);
1555        }
1556    }
1557    SetContentRect(rcRet);
1558    return rcRet;
1559}
1560FX_FLOAT CPDF_VariableText::GetAutoFontSize()
1561{
1562    FX_INT32 nTotal = sizeof(gFontSizeSteps) / sizeof(FX_BYTE);
1563    if (IsMultiLine()) {
1564        nTotal /= 4;
1565    }
1566    if (nTotal <= 0) {
1567        return 0;
1568    }
1569    if (GetPlateWidth() <= 0) {
1570        return 0;
1571    }
1572    FX_INT32 nLeft = 0;
1573    FX_INT32 nRight = nTotal - 1;
1574    FX_INT32 nMid = nTotal / 2;
1575    while (nLeft <= nRight) {
1576        if (IsBigger(gFontSizeSteps[nMid])) {
1577            nRight = nMid - 1;
1578            nMid = (nLeft + nRight) / 2;
1579            continue;
1580        } else {
1581            nLeft = nMid + 1;
1582            nMid = (nLeft + nRight) / 2;
1583            continue;
1584        }
1585    }
1586    return (FX_FLOAT)gFontSizeSteps[nMid];
1587}
1588FX_BOOL	CPDF_VariableText::IsBigger(FX_FLOAT fFontSize)
1589{
1590    FX_BOOL bBigger =  FALSE;
1591    CPVT_Size szTotal;
1592    for (FX_INT32 s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) {
1593        if (CSection * pSection = m_SectionArray.GetAt(s)) {
1594            CPVT_Size size = pSection->GetSectionSize(fFontSize);
1595            szTotal.x = FPDF_MAX(size.x, szTotal.x);
1596            szTotal.y += size.y;
1597            if (IsFloatBigger(szTotal.x, GetPlateWidth())
1598                    || IsFloatBigger(szTotal.y, GetPlateHeight())
1599               ) {
1600                bBigger = TRUE;
1601                break;
1602            }
1603        }
1604    }
1605    return bBigger;
1606}
1607CPVT_FloatRect CPDF_VariableText::RearrangeSections(const CPVT_WordRange & PlaceRange)
1608{
1609    CPVT_WordPlace place;
1610    FX_FLOAT fPosY = 0;
1611    FX_FLOAT fOldHeight;
1612    FX_INT32 nSSecIndex = PlaceRange.BeginPos.nSecIndex;
1613    FX_INT32 nESecIndex = PlaceRange.EndPos.nSecIndex;
1614    CPVT_FloatRect rcRet;
1615    for (FX_INT32 s = 0, sz = m_SectionArray.GetSize(); s < sz; s++) {
1616        place.nSecIndex = s;
1617        if (CSection * pSection = m_SectionArray.GetAt(s)) {
1618            pSection->SecPlace = place;
1619            CPVT_FloatRect rcSec = pSection->m_SecInfo.rcSection;
1620            if (s >= nSSecIndex) {
1621                if (s <= nESecIndex) {
1622                    rcSec = pSection->Rearrange();
1623                    rcSec.top += fPosY;
1624                    rcSec.bottom += fPosY;
1625                } else {
1626                    fOldHeight = pSection->m_SecInfo.rcSection.bottom - pSection->m_SecInfo.rcSection.top;
1627                    rcSec.top = fPosY;
1628                    rcSec.bottom = fPosY + fOldHeight;
1629                }
1630                pSection->m_SecInfo.rcSection = rcSec;
1631                pSection->ResetLinePlace();
1632            }
1633            if (s == 0) {
1634                rcRet = rcSec;
1635            } else {
1636                rcRet.left = FPDF_MIN(rcSec.left, rcRet.left);
1637                rcRet.top = FPDF_MIN(rcSec.top, rcRet.top);
1638                rcRet.right = FPDF_MAX(rcSec.right, rcRet.right);
1639                rcRet.bottom = FPDF_MAX(rcSec.bottom, rcRet.bottom);
1640            }
1641            fPosY += rcSec.Height();
1642        }
1643    }
1644    return rcRet;
1645}
1646FX_INT32 CPDF_VariableText::GetCharWidth(FX_INT32 nFontIndex, FX_WORD Word, FX_WORD SubWord, FX_INT32 nWordStyle)
1647{
1648    if (m_pVTProvider) {
1649        if (SubWord > 0) {
1650            return m_pVTProvider->GetCharWidth(nFontIndex, SubWord, nWordStyle);
1651        } else {
1652            return m_pVTProvider->GetCharWidth(nFontIndex, Word, nWordStyle);
1653        }
1654    }
1655    return 0;
1656}
1657FX_INT32 CPDF_VariableText::GetTypeAscent(FX_INT32 nFontIndex)
1658{
1659    return m_pVTProvider ? m_pVTProvider->GetTypeAscent(nFontIndex) : 0;
1660}
1661FX_INT32 CPDF_VariableText::GetTypeDescent(FX_INT32 nFontIndex)
1662{
1663    return m_pVTProvider ? m_pVTProvider->GetTypeDescent(nFontIndex) : 0;
1664}
1665FX_INT32 CPDF_VariableText::GetWordFontIndex(FX_WORD word, FX_INT32 charset, FX_INT32 nFontIndex)
1666{
1667    return m_pVTProvider ? m_pVTProvider->GetWordFontIndex(word, charset, nFontIndex) : -1;
1668}
1669FX_INT32 CPDF_VariableText::GetDefaultFontIndex()
1670{
1671    return m_pVTProvider ? m_pVTProvider->GetDefaultFontIndex() : -1;
1672}
1673FX_BOOL	CPDF_VariableText::IsLatinWord(FX_WORD word)
1674{
1675    return m_pVTProvider ? m_pVTProvider->IsLatinWord(word) : FALSE;
1676}
1677IPDF_VariableText_Iterator * CPDF_VariableText::GetIterator()
1678{
1679    if (!m_pVTIterator) {
1680        return m_pVTIterator = FX_NEW CPDF_VariableText_Iterator(this);
1681    }
1682    return m_pVTIterator;
1683}
1684IPDF_VariableText_Provider*	CPDF_VariableText::SetProvider(IPDF_VariableText_Provider * pProvider)
1685{
1686    IPDF_VariableText_Provider* pOld = m_pVTProvider;
1687    m_pVTProvider = pProvider;
1688    return pOld;
1689}
1690CPDF_VariableText_Iterator::CPDF_VariableText_Iterator(CPDF_VariableText * pVT):
1691    m_pVT(pVT),
1692    m_CurPos(-1, -1, -1)
1693{
1694}
1695CPDF_VariableText_Iterator::~CPDF_VariableText_Iterator()
1696{
1697}
1698void CPDF_VariableText_Iterator::SetAt(FX_INT32 nWordIndex)
1699{
1700    ASSERT(m_pVT != NULL);
1701    m_CurPos = m_pVT->WordIndexToWordPlace(nWordIndex);
1702}
1703void CPDF_VariableText_Iterator::SetAt(const CPVT_WordPlace & place)
1704{
1705    ASSERT(m_pVT != NULL);
1706    m_CurPos = place;
1707}
1708FX_BOOL	CPDF_VariableText_Iterator::NextWord()
1709{
1710    ASSERT(m_pVT != NULL);
1711    if (m_CurPos == m_pVT->GetEndWordPlace()) {
1712        return FALSE;
1713    }
1714    m_CurPos = m_pVT->GetNextWordPlace(m_CurPos);
1715    return TRUE;
1716}
1717FX_BOOL	CPDF_VariableText_Iterator::PrevWord()
1718{
1719    ASSERT(m_pVT != NULL);
1720    if (m_CurPos == m_pVT->GetBeginWordPlace()) {
1721        return FALSE;
1722    }
1723    m_CurPos = m_pVT->GetPrevWordPlace(m_CurPos);
1724    return TRUE;
1725}
1726FX_BOOL	CPDF_VariableText_Iterator::NextLine()
1727{
1728    ASSERT(m_pVT != NULL);
1729    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1730        if (m_CurPos.nLineIndex < pSection->m_LineArray.GetSize() - 1) {
1731            m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex + 1, -1);
1732            return TRUE;
1733        } else {
1734            if (m_CurPos.nSecIndex < m_pVT->m_SectionArray.GetSize() - 1) {
1735                m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1);
1736                return TRUE;
1737            }
1738        }
1739    }
1740    return FALSE;
1741}
1742FX_BOOL	CPDF_VariableText_Iterator::PrevLine()
1743{
1744    ASSERT(m_pVT != NULL);
1745    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1746        if (m_CurPos.nLineIndex > 0) {
1747            m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex - 1, -1);
1748            return TRUE;
1749        } else {
1750            if (m_CurPos.nSecIndex > 0) {
1751                if (CSection * pLastSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex - 1)) {
1752                    m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex - 1, pLastSection->m_LineArray.GetSize() - 1, -1);
1753                    return TRUE;
1754                }
1755            }
1756        }
1757    }
1758    return FALSE;
1759}
1760FX_BOOL	CPDF_VariableText_Iterator::NextSection()
1761{
1762    ASSERT(m_pVT != NULL);
1763    if (m_CurPos.nSecIndex < m_pVT->m_SectionArray.GetSize() - 1) {
1764        m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex + 1, 0, -1);
1765        return TRUE;
1766    }
1767    return FALSE;
1768}
1769FX_BOOL	CPDF_VariableText_Iterator::PrevSection()
1770{
1771    ASSERT(m_pVT != NULL);
1772    if (m_CurPos.nSecIndex > 0) {
1773        m_CurPos = CPVT_WordPlace(m_CurPos.nSecIndex - 1, 0, -1);
1774        return TRUE;
1775    }
1776    return FALSE;
1777}
1778FX_BOOL	CPDF_VariableText_Iterator::GetWord(CPVT_Word & word) const
1779{
1780    ASSERT(m_pVT != NULL);
1781    word.WordPlace = m_CurPos;
1782    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1783        if (CLine * pLine = pSection->m_LineArray.GetAt(m_CurPos.nLineIndex)) {
1784            if (CPVT_WordInfo * pWord = pSection->m_WordArray.GetAt(m_CurPos.nWordIndex)) {
1785                word.Word = pWord->Word;
1786                word.nCharset = pWord->nCharset;
1787                word.fWidth = m_pVT->GetWordWidth(*pWord);
1788                word.ptWord = m_pVT->InToOut(
1789                                  CPDF_Point(pWord->fWordX + pSection->m_SecInfo.rcSection.left,
1790                                             pWord->fWordY + pSection->m_SecInfo.rcSection.top) );
1791                word.fAscent = m_pVT->GetWordAscent(*pWord);
1792                word.fDescent = m_pVT->GetWordDescent(*pWord);
1793                if (pWord->pWordProps) {
1794                    word.WordProps = *pWord->pWordProps;
1795                }
1796                word.nFontIndex = m_pVT->GetWordFontIndex(*pWord);
1797                word.fFontSize = m_pVT->GetWordFontSize(*pWord);
1798                return TRUE;
1799            }
1800        }
1801    }
1802    return FALSE;
1803}
1804FX_BOOL	CPDF_VariableText_Iterator::SetWord(const CPVT_Word & word)
1805{
1806    ASSERT(m_pVT != NULL);
1807    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1808        if (CPVT_WordInfo * pWord = pSection->m_WordArray.GetAt(m_CurPos.nWordIndex)) {
1809            if (pWord->pWordProps) {
1810                *pWord->pWordProps = word.WordProps;
1811            }
1812            return TRUE;
1813        }
1814    }
1815    return FALSE;
1816}
1817FX_BOOL	CPDF_VariableText_Iterator::GetLine(CPVT_Line & line) const
1818{
1819    ASSERT(m_pVT != NULL);
1820    line.lineplace = CPVT_WordPlace(m_CurPos.nSecIndex, m_CurPos.nLineIndex, -1);
1821    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1822        if (CLine * pLine = pSection->m_LineArray.GetAt(m_CurPos.nLineIndex)) {
1823            line.ptLine = m_pVT->InToOut(
1824                              CPDF_Point(pLine->m_LineInfo.fLineX + pSection->m_SecInfo.rcSection.left,
1825                                         pLine->m_LineInfo.fLineY + pSection->m_SecInfo.rcSection.top) );
1826            line.fLineWidth = pLine->m_LineInfo.fLineWidth;
1827            line.fLineAscent = pLine->m_LineInfo.fLineAscent;
1828            line.fLineDescent = pLine->m_LineInfo.fLineDescent;
1829            line.lineEnd = pLine->GetEndWordPlace();
1830            return TRUE;
1831        }
1832    }
1833    return FALSE;
1834}
1835FX_BOOL	CPDF_VariableText_Iterator::GetSection(CPVT_Section & section) const
1836{
1837    ASSERT(m_pVT != NULL);
1838    section.secplace = CPVT_WordPlace(m_CurPos.nSecIndex, 0, -1);
1839    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1840        section.rcSection = m_pVT->InToOut(pSection->m_SecInfo.rcSection);
1841        if (pSection->m_SecInfo.pSecProps) {
1842            section.SecProps = *pSection->m_SecInfo.pSecProps;
1843        }
1844        if (pSection->m_SecInfo.pWordProps) {
1845            section.WordProps = *pSection->m_SecInfo.pWordProps;
1846        }
1847        return TRUE;
1848    }
1849    return FALSE;
1850}
1851FX_BOOL	CPDF_VariableText_Iterator::SetSection(const CPVT_Section & section)
1852{
1853    ASSERT(m_pVT != NULL);
1854    if (CSection * pSection = m_pVT->m_SectionArray.GetAt(m_CurPos.nSecIndex)) {
1855        if (pSection->m_SecInfo.pSecProps) {
1856            *pSection->m_SecInfo.pSecProps = section.SecProps;
1857        }
1858        if (pSection->m_SecInfo.pWordProps) {
1859            *pSection->m_SecInfo.pWordProps = section.WordProps;
1860        }
1861        return TRUE;
1862    }
1863    return FALSE;
1864}
1865