1/*
2 *
3 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
4 *
5 */
6
7#include "LETypes.h"
8#include "LEFontInstance.h"
9#include "OpenTypeTables.h"
10#include "ValueRecords.h"
11#include "DeviceTables.h"
12#include "GlyphIterator.h"
13#include "LESwaps.h"
14
15U_NAMESPACE_BEGIN
16
17#define Nibble(value, nibble) ((value >> (nibble * 4)) & 0xF)
18#define NibbleBits(value, nibble) (bitsInNibble[Nibble(value, nibble)])
19
20le_int16 ValueRecord::getFieldValue(ValueFormat valueFormat, ValueRecordField field) const
21{
22    le_int16 valueIndex = getFieldIndex(valueFormat, field);
23    le_int16 value = values[valueIndex];
24
25    return SWAPW(value);
26}
27
28le_int16 ValueRecord::getFieldValue(le_int16 index, ValueFormat valueFormat, ValueRecordField field) const
29{
30    le_int16 baseIndex = getFieldCount(valueFormat) * index;
31    le_int16 valueIndex = getFieldIndex(valueFormat, field);
32    le_int16 value = values[baseIndex + valueIndex];
33
34    return SWAPW(value);
35}
36
37void ValueRecord::adjustPosition(ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
38                                 const LEFontInstance *fontInstance) const
39{
40    float xPlacementAdjustment = 0;
41    float yPlacementAdjustment = 0;
42    float xAdvanceAdjustment   = 0;
43    float yAdvanceAdjustment   = 0;
44
45    if ((valueFormat & vfbXPlacement) != 0) {
46        le_int16 value = getFieldValue(valueFormat, vrfXPlacement);
47        LEPoint pixels;
48
49        fontInstance->transformFunits(value, 0, pixels);
50
51        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
52        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
53    }
54
55    if ((valueFormat & vfbYPlacement) != 0) {
56        le_int16 value = getFieldValue(valueFormat, vrfYPlacement);
57        LEPoint pixels;
58
59        fontInstance->transformFunits(0, value, pixels);
60
61        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
62        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
63    }
64
65    if ((valueFormat & vfbXAdvance) != 0) {
66        le_int16 value = getFieldValue(valueFormat, vrfXAdvance);
67        LEPoint pixels;
68
69        fontInstance->transformFunits(value, 0, pixels);
70
71        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
72        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
73    }
74
75    if ((valueFormat & vfbYAdvance) != 0) {
76        le_int16 value = getFieldValue(valueFormat, vrfYAdvance);
77        LEPoint pixels;
78
79        fontInstance->transformFunits(0, value, pixels);
80
81        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
82        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
83    }
84
85    // FIXME: The device adjustments should really be transformed, but
86    // the only way I know how to do that is to convert them to le_int16 units,
87    // transform them, and then convert them back to pixels. Sigh...
88    if ((valueFormat & vfbAnyDevice) != 0) {
89        le_int16 xppem = (le_int16) fontInstance->getXPixelsPerEm();
90        le_int16 yppem = (le_int16) fontInstance->getYPixelsPerEm();
91
92        if ((valueFormat & vfbXPlaDevice) != 0) {
93            Offset dtOffset = getFieldValue(valueFormat, vrfXPlaDevice);
94
95            if (dtOffset != 0) {
96                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
97                le_int16 xAdj = dt->getAdjustment(xppem);
98
99                xPlacementAdjustment += fontInstance->xPixelsToUnits(xAdj);
100            }
101        }
102
103        if ((valueFormat & vfbYPlaDevice) != 0) {
104            Offset dtOffset = getFieldValue(valueFormat, vrfYPlaDevice);
105
106            if (dtOffset != 0) {
107                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
108                le_int16 yAdj = dt->getAdjustment(yppem);
109
110                yPlacementAdjustment += fontInstance->yPixelsToUnits(yAdj);
111            }
112        }
113
114        if ((valueFormat & vfbXAdvDevice) != 0) {
115            Offset dtOffset = getFieldValue(valueFormat, vrfXAdvDevice);
116
117            if (dtOffset != 0) {
118                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
119                le_int16 xAdj = dt->getAdjustment(xppem);
120
121                xAdvanceAdjustment += fontInstance->xPixelsToUnits(xAdj);
122            }
123        }
124
125        if ((valueFormat & vfbYAdvDevice) != 0) {
126            Offset dtOffset = getFieldValue(valueFormat, vrfYAdvDevice);
127
128            if (dtOffset != 0) {
129                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
130                le_int16 yAdj = dt->getAdjustment(yppem);
131
132                yAdvanceAdjustment += fontInstance->yPixelsToUnits(yAdj);
133            }
134        }
135    }
136
137    glyphIterator.adjustCurrGlyphPositionAdjustment(
138        xPlacementAdjustment, yPlacementAdjustment, xAdvanceAdjustment, yAdvanceAdjustment);
139}
140
141void ValueRecord::adjustPosition(le_int16 index, ValueFormat valueFormat, const char *base, GlyphIterator &glyphIterator,
142                                 const LEFontInstance *fontInstance) const
143{
144    float xPlacementAdjustment = 0;
145    float yPlacementAdjustment = 0;
146    float xAdvanceAdjustment   = 0;
147    float yAdvanceAdjustment   = 0;
148
149    if ((valueFormat & vfbXPlacement) != 0) {
150        le_int16 value = getFieldValue(index, valueFormat, vrfXPlacement);
151        LEPoint pixels;
152
153        fontInstance->transformFunits(value, 0, pixels);
154
155        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
156        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
157    }
158
159    if ((valueFormat & vfbYPlacement) != 0) {
160        le_int16 value = getFieldValue(index, valueFormat, vrfYPlacement);
161        LEPoint pixels;
162
163        fontInstance->transformFunits(0, value, pixels);
164
165        xPlacementAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
166        yPlacementAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
167    }
168
169    if ((valueFormat & vfbXAdvance) != 0) {
170        le_int16 value = getFieldValue(index, valueFormat, vrfXAdvance);
171        LEPoint pixels;
172
173        fontInstance->transformFunits(value, 0, pixels);
174
175        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
176        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
177    }
178
179    if ((valueFormat & vfbYAdvance) != 0) {
180        le_int16 value = getFieldValue(index, valueFormat, vrfYAdvance);
181        LEPoint pixels;
182
183        fontInstance->transformFunits(0, value, pixels);
184
185        xAdvanceAdjustment += fontInstance->xPixelsToUnits(pixels.fX);
186        yAdvanceAdjustment += fontInstance->yPixelsToUnits(pixels.fY);
187    }
188
189    // FIXME: The device adjustments should really be transformed, but
190    // the only way I know how to do that is to convert them to le_int16 units,
191    // transform them, and then convert them back to pixels. Sigh...
192    if ((valueFormat & vfbAnyDevice) != 0) {
193        le_int16 xppem = (le_int16) fontInstance->getXPixelsPerEm();
194        le_int16 yppem = (le_int16) fontInstance->getYPixelsPerEm();
195
196        if ((valueFormat & vfbXPlaDevice) != 0) {
197            Offset dtOffset = getFieldValue(index, valueFormat, vrfXPlaDevice);
198
199            if (dtOffset != 0) {
200                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
201                le_int16 xAdj = dt->getAdjustment(xppem);
202
203                xPlacementAdjustment += fontInstance->xPixelsToUnits(xAdj);
204            }
205        }
206
207        if ((valueFormat & vfbYPlaDevice) != 0) {
208            Offset dtOffset = getFieldValue(index, valueFormat, vrfYPlaDevice);
209
210            if (dtOffset != 0) {
211                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
212                le_int16 yAdj = dt->getAdjustment(yppem);
213
214                yPlacementAdjustment += fontInstance->yPixelsToUnits(yAdj);
215            }
216        }
217
218        if ((valueFormat & vfbXAdvDevice) != 0) {
219            Offset dtOffset = getFieldValue(index, valueFormat, vrfXAdvDevice);
220
221            if (dtOffset != 0) {
222                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
223                le_int16 xAdj = dt->getAdjustment(xppem);
224
225                xAdvanceAdjustment += fontInstance->xPixelsToUnits(xAdj);
226            }
227        }
228
229        if ((valueFormat & vfbYAdvDevice) != 0) {
230            Offset dtOffset = getFieldValue(index, valueFormat, vrfYAdvDevice);
231
232            if (dtOffset != 0) {
233                const DeviceTable *dt = (const DeviceTable *) (base + dtOffset);
234                le_int16 yAdj = dt->getAdjustment(yppem);
235
236                yAdvanceAdjustment += fontInstance->yPixelsToUnits(yAdj);
237            }
238        }
239    }
240
241    glyphIterator.adjustCurrGlyphPositionAdjustment(
242        xPlacementAdjustment, yPlacementAdjustment, xAdvanceAdjustment, yAdvanceAdjustment);
243}
244
245le_int16 ValueRecord::getSize(ValueFormat valueFormat)
246{
247    return getFieldCount(valueFormat) * sizeof(le_int16);
248}
249
250le_int16 ValueRecord::getFieldCount(ValueFormat valueFormat)
251{
252    static const le_int16 bitsInNibble[] =
253    {
254        0 + 0 + 0 + 0,
255        0 + 0 + 0 + 1,
256        0 + 0 + 1 + 0,
257        0 + 0 + 1 + 1,
258        0 + 1 + 0 + 0,
259        0 + 1 + 0 + 1,
260        0 + 1 + 1 + 0,
261        0 + 1 + 1 + 1,
262        1 + 0 + 0 + 0,
263        1 + 0 + 0 + 1,
264        1 + 0 + 1 + 0,
265        1 + 0 + 1 + 1,
266        1 + 1 + 0 + 0,
267        1 + 1 + 0 + 1,
268        1 + 1 + 1 + 0,
269        1 + 1 + 1 + 1
270    };
271
272    valueFormat &= ~vfbReserved;
273
274    return NibbleBits(valueFormat, 0) + NibbleBits(valueFormat, 1) +
275           NibbleBits(valueFormat, 2) + NibbleBits(valueFormat, 3);
276}
277
278le_int16 ValueRecord::getFieldIndex(ValueFormat valueFormat, ValueRecordField field)
279{
280    static const le_uint16 beforeMasks[] =
281    {
282        0x0000,
283        0x0001,
284        0x0003,
285        0x0007,
286        0x000F,
287        0x001F,
288        0x003F,
289        0x007F,
290        0x00FF,
291        0x01FF,
292        0x03FF,
293        0x07FF,
294        0x0FFF,
295        0x1FFF,
296        0x3FFF,
297        0x7FFF,
298        0xFFFF
299    };
300
301    return getFieldCount(valueFormat & beforeMasks[field]);
302}
303
304U_NAMESPACE_END
305