1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26/* 27 * 28 * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved 29 * 30 */ 31 32#include "LETypes.h" 33#include "LEFontInstance.h" 34#include "OpenTypeTables.h" 35#include "AnchorTables.h" 36#include "MarkArrays.h" 37#include "GlyphPositioningTables.h" 38#include "AttachmentPosnSubtables.h" 39#include "MarkToBasePosnSubtables.h" 40#include "GlyphIterator.h" 41#include "LESwaps.h" 42 43U_NAMESPACE_BEGIN 44 45LEGlyphID MarkToBasePositioningSubtable::findBaseGlyph(GlyphIterator *glyphIterator) const 46{ 47 if (glyphIterator->prev()) { 48 return glyphIterator->getCurrGlyphID(); 49 } 50 51 return 0xFFFF; 52} 53 54le_int32 MarkToBasePositioningSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const 55{ 56 LEGlyphID markGlyph = glyphIterator->getCurrGlyphID(); 57 le_int32 markCoverage = getGlyphCoverage(base, (LEGlyphID) markGlyph, success); 58 59 if (LE_FAILURE(success)) { 60 return 0; 61 } 62 63 if (markCoverage < 0) { 64 // markGlyph isn't a covered mark glyph 65 return 0; 66 } 67 68 LEPoint markAnchor; 69 LEReferenceTo<MarkArray> markArray(base, success, (const MarkArray *) ((char *) this + SWAPW(markArrayOffset))); 70 if(LE_FAILURE(success)) return 0; 71 le_int32 markClass = markArray->getMarkClass(markArray, markGlyph, markCoverage, fontInstance, markAnchor, success); 72 le_uint16 mcCount = SWAPW(classCount); 73 74 if (markClass < 0 || markClass >= mcCount || LE_FAILURE(success)) { 75 // markGlyph isn't in the mark array or its 76 // mark class is too big. The table is mal-formed! 77 return 0; 78 } 79 80 // FIXME: We probably don't want to find a base glyph before a previous ligature... 81 GlyphIterator baseIterator(*glyphIterator, (le_uint16) (lfIgnoreMarks /*| lfIgnoreLigatures*/)); 82 LEGlyphID baseGlyph = findBaseGlyph(&baseIterator); 83 le_int32 baseCoverage = getBaseCoverage(base, (LEGlyphID) baseGlyph, success); 84 LEReferenceTo<BaseArray> baseArray(base, success, (const BaseArray *) ((char *) this + SWAPW(baseArrayOffset))); 85 if(LE_FAILURE(success)) return 0; 86 le_uint16 baseCount = SWAPW(baseArray->baseRecordCount); 87 88 if (baseCoverage < 0 || baseCoverage >= baseCount) { 89 // The base glyph isn't covered, or the coverage 90 // index is too big. The latter means that the 91 // table is mal-formed... 92 return 0; 93 } 94 LEReferenceTo<BaseRecord> baseRecord(base, success, &baseArray->baseRecordArray[baseCoverage * mcCount]); 95 if( LE_FAILURE(success) ) { return 0; } 96 LEReferenceToArrayOf<Offset> baseAnchorTableOffsetArray(base, success, &(baseRecord->baseAnchorTableOffsetArray[0]), mcCount); 97 98 if( LE_FAILURE(success) ) { return 0; } 99 Offset anchorTableOffset = SWAPW(baseRecord->baseAnchorTableOffsetArray[markClass]); 100 LEReferenceTo<AnchorTable> anchorTable(baseArray, success, anchorTableOffset); 101 if( LE_FAILURE(success) ) { return 0; } 102 103 LEPoint baseAnchor, markAdvance, pixels; 104 105 106 anchorTable->getAnchor(anchorTable, baseGlyph, fontInstance, baseAnchor, success); 107 108 fontInstance->getGlyphAdvance(markGlyph, pixels); 109 fontInstance->pixelsToUnits(pixels, markAdvance); 110 111 float anchorDiffX = baseAnchor.fX - markAnchor.fX; 112 float anchorDiffY = baseAnchor.fY - markAnchor.fY; 113 114 _LETRACE("Offset: (%.2f, %.2f) glyph 0x%X", anchorDiffX, anchorDiffY, markGlyph); 115 116 glyphIterator->setCurrGlyphBaseOffset(baseIterator.getCurrStreamPosition()); 117 118 if (glyphIterator->isRightToLeft()) { 119 // FIXME: need similar patch to below; also in MarkToLigature and MarkToMark 120 // (is there a better way to approach this for all the cases?) 121 glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX, anchorDiffY, -markAdvance.fX, -markAdvance.fY); 122 } else { 123 LEPoint baseAdvance; 124 125 fontInstance->getGlyphAdvance(baseGlyph, pixels); 126 127 //JK: adjustment needs to account for non-zero advance of any marks between base glyph and current mark 128 GlyphIterator gi(baseIterator, (le_uint16)0); // copy of baseIterator that won't ignore marks 129 gi.next(); // point beyond the base glyph 130 while (gi.getCurrStreamPosition() < glyphIterator->getCurrStreamPosition()) { // for all intervening glyphs (marks)... 131 LEGlyphID otherMark = gi.getCurrGlyphID(); 132 LEPoint px; 133 fontInstance->getGlyphAdvance(otherMark, px); // get advance, in case it's non-zero 134 pixels.fX += px.fX; // and add that to the base glyph's advance 135 pixels.fY += px.fY; 136 gi.next(); 137 } 138 // end of JK patch 139 fontInstance->pixelsToUnits(pixels, baseAdvance); 140 141 glyphIterator->setCurrGlyphPositionAdjustment(anchorDiffX - baseAdvance.fX, anchorDiffY - baseAdvance.fY, -markAdvance.fX, -markAdvance.fY); 142 } 143 144 return 1; 145} 146 147U_NAMESPACE_END 148