1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "LETypes.h"
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "LEFontInstance.h"
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "OpenTypeTables.h"
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "AnchorTables.h"
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "MarkArrays.h"
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "GlyphPositioningTables.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "AttachmentPosnSubtables.h"
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "MarkToBasePosnSubtables.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "GlyphIterator.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "LESwaps.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruLEGlyphID MarkToBasePositioningSubtable::findBaseGlyph(GlyphIterator *glyphIterator) const
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (glyphIterator->prev()) {
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return glyphIterator->getCurrGlyphID();
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return 0xFFFF;
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querule_int32 MarkToBasePositioningSubtable::process(GlyphIterator *glyphIterator, const LEFontInstance *fontInstance) const
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEGlyphID markGlyph = glyphIterator->getCurrGlyphID();
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 markCoverage = getGlyphCoverage((LEGlyphID) markGlyph);
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (markCoverage < 0) {
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // markGlyph isn't a covered mark glyph
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEPoint markAnchor;
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const MarkArray *markArray = (const MarkArray *) ((char *) this + SWAPW(markArrayOffset));
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 markClass = markArray->getMarkClass(markGlyph, markCoverage, fontInstance, markAnchor);
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_uint16 mcCount = SWAPW(classCount);
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (markClass < 0 || markClass >= mcCount) {
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // markGlyph isn't in the mark array or its
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // mark class is too big. The table is mal-formed!
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // FIXME: We probably don't want to find a base glyph before a previous ligature...
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/));
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEGlyphID baseGlyph = findBaseGlyph(&baseIterator);
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_int32 baseCoverage = getBaseCoverage((LEGlyphID) baseGlyph);
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const BaseArray *baseArray = (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset));
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    le_uint16 baseCount = SWAPW(baseArray->baseRecordCount);
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (baseCoverage < 0 || baseCoverage >= baseCount) {
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // The base glyph isn't covered, or the coverage
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // index is too big. The latter means that the
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // table is mal-formed...
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const BaseRecord *baseRecord = &baseArray->baseRecordArray[baseCoverage * mcCount];
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    Offset anchorTableOffset = SWAPW(baseRecord->baseAnchorTableOffsetArray[markClass]);
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const AnchorTable *anchorTable = (const AnchorTable *) ((char *) baseArray + anchorTableOffset);
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    LEPoint baseAnchor, markAdvance, pixels;
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (anchorTableOffset == 0) {
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // this means the table is mal-formed...
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        glyphIterator->setCurrGlyphBaseOffset(baseIterator.getCurrStreamPosition());
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    anchorTable->getAnchor(baseGlyph, fontInstance, baseAnchor);
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fontInstance->getGlyphAdvance(markGlyph, pixels);
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    fontInstance->pixelsToUnits(pixels, markAdvance);
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float anchorDiffX = baseAnchor.fX - markAnchor.fX;
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float anchorDiffY = baseAnchor.fY - markAnchor.fY;
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    glyphIterator->setCurrGlyphBaseOffset(baseIterator.getCurrStreamPosition());
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (glyphIterator->isRightToLeft()) {
8650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // FIXME: need similar patch to below; also in MarkToLigature and MarkToMark
8750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // (is there a better way to approach this for all the cases?)
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX, anchorDiffY, -markAdvance.fX, -markAdvance.fY);
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        LEPoint baseAdvance;
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fontInstance->getGlyphAdvance(baseGlyph, pixels);
9350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
9450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        //JK: adjustment needs to account for non-zero advance of any marks between base glyph and current mark
9550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        GlyphIterator gi(baseIterator, (le_uint16)0); // copy of baseIterator that won't ignore marks
9650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        gi.next(); // point beyond the base glyph
9750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        while (gi.getCurrStreamPosition() < glyphIterator->getCurrStreamPosition()) { // for all intervening glyphs (marks)...
9850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            LEGlyphID otherMark = gi.getCurrGlyphID();
9950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            LEPoint px;
10050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            fontInstance->getGlyphAdvance(otherMark, px); // get advance, in case it's non-zero
10150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            pixels.fX += px.fX; // and add that to the base glyph's advance
10250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            pixels.fY += px.fY;
10350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            gi.next();
10450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
10550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // end of JK patch
10650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fontInstance->pixelsToUnits(pixels, baseAdvance);
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX - baseAdvance.fX, anchorDiffY - baseAdvance.fY, -markAdvance.fX, -markAdvance.fY);
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return 1;
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
116