1/*
2 *
3 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
4 *
5 */
6
7#include "LETypes.h"
8#include "GlyphPositionAdjustments.h"
9#include "LEGlyphStorage.h"
10#include "LEFontInstance.h"
11
12U_NAMESPACE_BEGIN
13
14#define CHECK_ALLOCATE_ARRAY(array, type, size) \
15    if (array == NULL) { \
16        array = (type *) new type[size]; \
17    }
18
19GlyphPositionAdjustments::GlyphPositionAdjustments(le_int32 glyphCount)
20    : fGlyphCount(glyphCount), fEntryExitPoints(NULL), fAdjustments(NULL)
21{
22    fAdjustments = (Adjustment *) new Adjustment[glyphCount];
23}
24
25GlyphPositionAdjustments::~GlyphPositionAdjustments()
26{
27    delete[] fEntryExitPoints;
28    delete[] fAdjustments;
29}
30
31const LEPoint *GlyphPositionAdjustments::getEntryPoint(le_int32 index, LEPoint &entryPoint) const
32{
33    if (fEntryExitPoints == NULL) {
34        return NULL;
35    }
36
37    return fEntryExitPoints[index].getEntryPoint(entryPoint);
38}
39
40const LEPoint *GlyphPositionAdjustments::getExitPoint(le_int32 index, LEPoint &exitPoint)const
41{
42    if (fEntryExitPoints == NULL) {
43        return NULL;
44    }
45
46    return fEntryExitPoints[index].getExitPoint(exitPoint);
47}
48
49void GlyphPositionAdjustments::clearEntryPoint(le_int32 index)
50{
51    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
52
53    fEntryExitPoints[index].clearEntryPoint();
54}
55
56void GlyphPositionAdjustments::clearExitPoint(le_int32 index)
57{
58    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
59
60    fEntryExitPoints[index].clearExitPoint();
61}
62
63void GlyphPositionAdjustments::setEntryPoint(le_int32 index, LEPoint &newEntryPoint, le_bool baselineIsLogicalEnd)
64{
65    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
66
67    fEntryExitPoints[index].setEntryPoint(newEntryPoint, baselineIsLogicalEnd);
68}
69
70void GlyphPositionAdjustments::setExitPoint(le_int32 index, LEPoint &newExitPoint, le_bool baselineIsLogicalEnd)
71{
72    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
73
74    fEntryExitPoints[index].setExitPoint(newExitPoint, baselineIsLogicalEnd);
75}
76
77void GlyphPositionAdjustments::setCursiveGlyph(le_int32 index, le_bool baselineIsLogicalEnd)
78{
79    CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
80
81    fEntryExitPoints[index].setCursiveGlyph(baselineIsLogicalEnd);
82}
83
84void GlyphPositionAdjustments::applyCursiveAdjustments(LEGlyphStorage &glyphStorage, le_bool rightToLeft, const LEFontInstance *fontInstance)
85{
86    if (! hasCursiveGlyphs()) {
87        return;
88    }
89
90    le_int32 start = 0, end = fGlyphCount, dir = 1;
91    le_int32 firstExitPoint = -1, lastExitPoint = -1;
92    LEPoint entryAnchor, exitAnchor, pixels;
93    LEGlyphID lastExitGlyphID = 0;
94    float baselineAdjustment = 0;
95
96    // This removes a possible warning about
97    // using exitAnchor before it's been initialized.
98    exitAnchor.fX = exitAnchor.fY = 0;
99
100    if (rightToLeft) {
101        start = fGlyphCount - 1;
102        end = -1;
103        dir = -1;
104    }
105
106    for (le_int32 i = start; i != end; i += dir) {
107        LEGlyphID glyphID = glyphStorage[i];
108
109        if (isCursiveGlyph(i)) {
110            if (lastExitPoint >= 0 && getEntryPoint(i, entryAnchor) != NULL) {
111                float anchorDiffX = exitAnchor.fX - entryAnchor.fX;
112                float anchorDiffY = exitAnchor.fY - entryAnchor.fY;
113
114                baselineAdjustment += anchorDiffY;
115                adjustYPlacement(i, baselineAdjustment);
116
117                if (rightToLeft) {
118                    LEPoint secondAdvance;
119
120                    fontInstance->getGlyphAdvance(glyphID, pixels);
121                    fontInstance->pixelsToUnits(pixels, secondAdvance);
122
123                    adjustXAdvance(i, -(anchorDiffX + secondAdvance.fX));
124                } else {
125                    LEPoint firstAdvance;
126
127                    fontInstance->getGlyphAdvance(lastExitGlyphID, pixels);
128                    fontInstance->pixelsToUnits(pixels, firstAdvance);
129
130                    adjustXAdvance(lastExitPoint, anchorDiffX - firstAdvance.fX);
131                }
132            }
133
134            lastExitPoint = i;
135
136            if (getExitPoint(i, exitAnchor) != NULL) {
137                if (firstExitPoint < 0) {
138                    firstExitPoint = i;
139                }
140
141                lastExitGlyphID = glyphID;
142            } else {
143                if (baselineIsLogicalEnd(i) && firstExitPoint >= 0 && lastExitPoint >= 0) {
144                    le_int32 limit = lastExitPoint /*+ dir*/;
145                    LEPoint dummyAnchor;
146
147                    if (getEntryPoint(i, dummyAnchor) != NULL) {
148                        limit += dir;
149                    }
150
151                    for (le_int32 j = firstExitPoint; j != limit; j += dir) {
152                        if (isCursiveGlyph(j)) {
153                            adjustYPlacement(j, -baselineAdjustment);
154                        }
155                    }
156                }
157
158                firstExitPoint = lastExitPoint = -1;
159                baselineAdjustment = 0;
160            }
161        }
162    }
163}
164
165LEPoint *GlyphPositionAdjustments::EntryExitPoint::getEntryPoint(LEPoint &entryPoint) const
166{
167    if (fFlags & EEF_HAS_ENTRY_POINT) {
168        entryPoint = fEntryPoint;
169        return &entryPoint;
170    }
171
172    return NULL;
173}
174
175LEPoint *GlyphPositionAdjustments::EntryExitPoint::getExitPoint(LEPoint &exitPoint) const
176{
177    if (fFlags & EEF_HAS_EXIT_POINT) {
178        exitPoint = fExitPoint;
179        return &exitPoint;
180    }
181
182    return NULL;
183}
184
185U_NAMESPACE_END
186