1/* 2 * Copyright (C) 2012, 2013 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "SimpleFontData.h" 21 22#include "FloatRect.h" 23#include "Font.h" 24#include "FontCache.h" 25#include "FontDescription.h" 26#include "ITypeUtils.h" 27 28#include <fs_api.h> 29#include <unicode/normlzr.h> 30 31namespace WebCore { 32 33static inline float FSFixedToFloat(FS_FIXED n) { return n / 65536.0; } 34 35#define openTypeTag(a, b, c, d) (FS_ULONG)((a << 24) | (b << 16) | (c << 8) | d) 36 37void SimpleFontData::platformInit() 38{ 39 FS_FIXED ascender = 0; 40 FS_FIXED descender = 0; 41 FS_FIXED leading = 0; 42 FsAscDescLeadSource source; 43 FS_LONG result; 44 if (m_platformData.size() > 0) { 45 // FIXME: hack! FS_get_ascender_descender_leading() returns ERR_NO_CURRENT_SFNT when size is 0, even though we called FS_set_scale and m_platformData.font()->cur_sfnt is not 0 46 result = FS_get_ascender_descender_leading(m_platformData.font(), &ascender, &descender, &leading, &source); 47 ASSERT_UNUSED(result, result == SUCCESS); 48 } 49 50 m_fontMetrics.setAscent(FS_ROUND(ascender)); 51 m_fontMetrics.setDescent(FS_ROUND(descender)); 52 m_fontMetrics.setLineGap(iTypeFixedToFloat(leading)); 53 m_fontMetrics.setLineSpacing(lroundf(m_fontMetrics.ascent()) + lroundf(m_fontMetrics.descent()) + lroundf(m_fontMetrics.lineGap())); 54 55 FONT_METRICS metrics; 56 result = FS_font_metrics(m_platformData.font(), &metrics); 57 ASSERT_UNUSED(result, result == SUCCESS); 58 59 // m_fontMetrics.setUnitsPerEm(FS_get_design_units(m_platformData().font())); 60 m_fontMetrics.setUnitsPerEm(metrics.unitsPerEm); 61 62 FS_USHORT xRange = metrics.font_bbox.xMax - metrics.font_bbox.xMin; 63 m_maxCharWidth = roundf((xRange * roundf(m_platformData.size())) / metrics.unitsPerEm); 64 65 TTF_OS2 os2; 66 if (FS_get_table_structure(m_platformData.font(), TAG_OS2, &os2) == SUCCESS && os2.sxHeight && os2.xAvgCharWidth) { 67 FS_USHORT yppem = m_platformData.font()->lpm; 68 m_fontMetrics.setXHeight(static_cast<float>(os2.sxHeight) * yppem / metrics.unitsPerEm); 69 m_avgCharWidth = static_cast<float>(os2.xAvgCharWidth) * yppem / metrics.unitsPerEm; 70 } else { 71 // HACK 72 m_fontMetrics.setXHeight(m_fontMetrics.ascent() * 0.56); 73 m_fontMetrics.setHasXHeight(false); 74 m_avgCharWidth = m_fontMetrics.xHeight(); 75 76 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 77 78 if (glyphPageZero) { 79 static const UChar32 xChar = 'x'; 80 const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(xChar).glyph; 81 82 if (xGlyph) { 83 // In widthForGlyph(), xGlyph will be compared with 84 // m_zeroWidthSpaceGlyph, which isn't initialized yet here. 85 // Initialize it with zero to make sure widthForGlyph() returns 86 // the right width. 87 m_zeroWidthSpaceGlyph = 0; 88 m_avgCharWidth = widthForGlyph(xGlyph); 89 } 90 } 91 } 92 93 if (m_platformData.orientation() == Vertical && !isTextOrientationFallback()) 94 m_hasVerticalGlyphs = FS_get_table(m_platformData.font(), openTypeTag('v', 'h', 'e', 'a'), TBL_QUERY, 0) 95 || FS_get_table(m_platformData.font(), openTypeTag('V', 'O', 'R', 'G'), TBL_QUERY, 0); 96} 97 98void SimpleFontData::platformCharWidthInit() 99{ 100} 101 102void SimpleFontData::platformDestroy() 103{ 104} 105 106PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const 107{ 108 const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor); 109 return adoptRef(new SimpleFontData( 110 FontPlatformData(m_platformData.font()->cur_lfnt->name, 111 scaledSize, 112 m_platformData.syntheticBold(), 113 m_platformData.syntheticOblique(), 114 m_platformData.orientation(), 115 m_platformData.widthVariant()), 116 isCustomFont(), false)); 117} 118 119bool SimpleFontData::containsCharacters(const UChar* characters, int length) const 120{ 121 int position = 0; 122 123 while (position < length) { 124 // FIXME: use shaper? 125 UChar32 character; 126 int nextPosition = position; 127 U16_NEXT(characters, nextPosition, length, character); 128 129 FS_USHORT glyph = FS_map_char(m_platformData.font(), static_cast<FS_ULONG>(character)); 130 if (!glyph) 131 return false; 132 133 position = nextPosition; 134 } 135 136 return true; 137} 138 139void SimpleFontData::determinePitch() 140{ 141 m_treatAsFixedPitch = m_platformData.isFixedPitch(); 142} 143 144FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const 145{ 146 FS_GLYPHMAP* glyphmap = FS_get_glyphmap(m_platformData.font(), glyph, FS_MAP_DISTANCEFIELD | FS_MAP_GRAYMAP8); 147 if (!glyphmap) 148 return FloatRect(); 149 150 FloatRect bounds(glyphmap->lo_x, glyphmap->height - glyphmap->hi_y, glyphmap->width, glyphmap->height); 151 FS_free_char(m_platformData.font(), glyphmap); 152 153 return bounds; 154} 155 156float SimpleFontData::platformWidthForGlyph(Glyph glyph) const 157{ 158 FS_SHORT idx, idy; 159 FS_FIXED dx, dy; 160 FS_FIXED s00, s01, s10, s11; 161 bool needsFakeBoldReset = m_platformData.syntheticBold() && m_treatAsFixedPitch; 162 163 if (needsFakeBoldReset) { 164 FS_get_scale(m_platformData.font(), &s00, &s01, &s10, &s11); 165 FS_set_bold_pct(m_platformData.font(), 0); 166 FS_set_scale(m_platformData.font(), s00, s01, s10, s11); 167 } 168 169 if (FS_get_advance(m_platformData.font(), glyph, FS_MAP_DISTANCEFIELD | FS_MAP_GRAYMAP8, &idx, &idy, &dx, &dy) != SUCCESS) 170 dx = 0; 171 172 if (needsFakeBoldReset) { 173 FS_set_bold_pct(m_platformData.font(), ITYPEFAKEBOLDAMOUNT); 174 FS_set_scale(m_platformData.font(), s00, s01, s10, s11); 175 } 176 177 return iTypeFixedToFloat(dx); 178} 179 180bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const 181{ 182 if (!m_combiningCharacterSequenceSupport) 183 m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>); 184 185 WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); 186 if (!addResult.isNewEntry) 187 return addResult.iterator->value; 188 189 UErrorCode error = U_ZERO_ERROR; 190 Vector<UChar, 4> normalizedCharacters(length); 191 int32_t normalizedLength = unorm_normalize(characters, length, UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], length, &error); 192 if (U_FAILURE(error)) 193 return false; 194 195 int position = 0; 196 while (position < normalizedLength) { 197 UChar32 character; 198 int nextPosition = position; 199 U16_NEXT(normalizedCharacters, nextPosition, normalizedLength, character); 200 201 if (!u_hasBinaryProperty(character, UCHAR_DEFAULT_IGNORABLE_CODE_POINT)) { 202 FS_USHORT glyph = FS_map_char(m_platformData.font(), static_cast<FS_ULONG>(character)); 203 if (!glyph) 204 return false; 205 } 206 207 position = nextPosition; 208 } 209 210 addResult.iterator->value = true; 211 return true; 212} 213 214} // namespace WebCore 215