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 
12 U_NAMESPACE_BEGIN
13 
14 #define CHECK_ALLOCATE_ARRAY(array, type, size) \
15     if (array == NULL) { \
16         array = (type *) new type[size]; \
17     }
18 
GlyphPositionAdjustments(le_int32 glyphCount)19 GlyphPositionAdjustments::GlyphPositionAdjustments(le_int32 glyphCount)
20     : fGlyphCount(glyphCount), fEntryExitPoints(NULL), fAdjustments(NULL)
21 {
22     fAdjustments = (Adjustment *) new Adjustment[glyphCount];
23 }
24 
~GlyphPositionAdjustments()25 GlyphPositionAdjustments::~GlyphPositionAdjustments()
26 {
27     delete[] fEntryExitPoints;
28     delete[] fAdjustments;
29 }
30 
getEntryPoint(le_int32 index,LEPoint & entryPoint) const31 const 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 
getExitPoint(le_int32 index,LEPoint & exitPoint) const40 const 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 
clearEntryPoint(le_int32 index)49 void GlyphPositionAdjustments::clearEntryPoint(le_int32 index)
50 {
51     CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
52 
53     fEntryExitPoints[index].clearEntryPoint();
54 }
55 
clearExitPoint(le_int32 index)56 void GlyphPositionAdjustments::clearExitPoint(le_int32 index)
57 {
58     CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
59 
60     fEntryExitPoints[index].clearExitPoint();
61 }
62 
setEntryPoint(le_int32 index,LEPoint & newEntryPoint,le_bool baselineIsLogicalEnd)63 void 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 
setExitPoint(le_int32 index,LEPoint & newExitPoint,le_bool baselineIsLogicalEnd)70 void 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 
setCursiveGlyph(le_int32 index,le_bool baselineIsLogicalEnd)77 void GlyphPositionAdjustments::setCursiveGlyph(le_int32 index, le_bool baselineIsLogicalEnd)
78 {
79     CHECK_ALLOCATE_ARRAY(fEntryExitPoints, EntryExitPoint, fGlyphCount);
80 
81     fEntryExitPoints[index].setCursiveGlyph(baselineIsLogicalEnd);
82 }
83 
applyCursiveAdjustments(LEGlyphStorage & glyphStorage,le_bool rightToLeft,const LEFontInstance * fontInstance)84 void 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 
getEntryPoint(LEPoint & entryPoint) const165 LEPoint *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 
getExitPoint(LEPoint & exitPoint) const175 LEPoint *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 
185 U_NAMESPACE_END
186