1 /* 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "platform/fonts/SimpleFontData.h" 33 34 #include <unicode/normlzr.h> 35 #include "SkPaint.h" 36 #include "SkPath.h" 37 #include "SkTypeface.h" 38 #include "SkTypes.h" 39 #include "platform/fonts/FontDescription.h" 40 #include "platform/fonts/VDMXParser.h" 41 #include "platform/geometry/FloatRect.h" 42 #include "wtf/unicode/Unicode.h" 43 44 #if OS(WIN) 45 #include "platform/win/HWndDC.h" 46 #endif 47 48 namespace WebCore { 49 50 // This is the largest VDMX table which we'll try to load and parse. 51 static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB 52 53 void SimpleFontData::platformInit() 54 { 55 if (!m_platformData.size()) { 56 m_fontMetrics.reset(); 57 m_avgCharWidth = 0; 58 m_maxCharWidth = 0; 59 return; 60 } 61 62 SkPaint paint; 63 SkPaint::FontMetrics metrics; 64 65 m_platformData.setupPaint(&paint); 66 paint.getFontMetrics(&metrics); 67 SkTypeface* face = paint.getTypeface(); 68 ASSERT(face); 69 70 static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); 71 int pixelSize = m_platformData.size() + 0.5; 72 int vdmxAscent, vdmxDescent; 73 bool isVDMXValid = false; 74 75 size_t vdmxSize = face->getTableSize(vdmxTag); 76 if (vdmxSize && vdmxSize < maxVDMXTableSize) { 77 uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); 78 if (vdmxTable 79 && face->getTableData(vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize 80 && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) 81 isVDMXValid = true; 82 fastFree(vdmxTable); 83 } 84 85 float ascent; 86 float descent; 87 88 // Beware those who step here: This code is designed to match Win32 font 89 // metrics *exactly* (except the adjustment of ascent/descent on Linux/Android). 90 if (isVDMXValid) { 91 ascent = vdmxAscent; 92 descent = -vdmxDescent; 93 } else { 94 ascent = SkScalarRound(-metrics.fAscent); 95 descent = SkScalarRound(metrics.fDescent); 96 #if OS(LINUX) || OS(ANDROID) 97 // When subpixel positioning is enabled, if the descent is rounded down, the descent part 98 // of the glyph may be truncated when displayed in a 'overflow: hidden' container. 99 // To avoid that, borrow 1 unit from the ascent when possible. 100 // FIXME: This can be removed if sub-pixel ascent/descent is supported. 101 if (platformData().fontRenderStyle().useSubpixelPositioning && descent < SkScalarToFloat(metrics.fDescent) && ascent >= 1) { 102 ++descent; 103 --ascent; 104 } 105 #endif 106 } 107 108 m_fontMetrics.setAscent(ascent); 109 m_fontMetrics.setDescent(descent); 110 111 float xHeight; 112 if (metrics.fXHeight) { 113 xHeight = metrics.fXHeight; 114 m_fontMetrics.setXHeight(xHeight); 115 } else { 116 xHeight = ascent * 0.56; // Best guess from Windows font metrics. 117 m_fontMetrics.setXHeight(xHeight); 118 m_fontMetrics.setHasXHeight(false); 119 } 120 121 float lineGap = SkScalarToFloat(metrics.fLeading); 122 m_fontMetrics.setLineGap(lineGap); 123 m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); 124 125 if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { 126 static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); 127 static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); 128 size_t vheaSize = face->getTableSize(vheaTag); 129 size_t vorgSize = face->getTableSize(vorgTag); 130 if ((vheaSize > 0) || (vorgSize > 0)) 131 m_hasVerticalGlyphs = true; 132 } 133 134 // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is 135 // calculated for us, but we need to calculate m_maxCharWidth and 136 // m_avgCharWidth in order for text entry widgets to be sized correctly. 137 #if OS(WIN) 138 m_maxCharWidth = SkScalarRound(metrics.fMaxCharWidth); 139 #else 140 // FIXME: This seems incorrect and should probably use fMaxCharWidth as 141 // the code path above. 142 SkScalar xRange = metrics.fXMax - metrics.fXMin; 143 m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); 144 #endif 145 146 if (metrics.fAvgCharWidth) 147 m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); 148 else { 149 m_avgCharWidth = xHeight; 150 151 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 152 153 if (glyphPageZero) { 154 static const UChar32 xChar = 'x'; 155 const Glyph xGlyph = glyphPageZero->glyphForCharacter(xChar); 156 157 if (xGlyph) { 158 // In widthForGlyph(), xGlyph will be compared with 159 // m_zeroWidthSpaceGlyph, which isn't initialized yet here. 160 // Initialize it with zero to make sure widthForGlyph() returns 161 // the right width. 162 m_zeroWidthSpaceGlyph = 0; 163 m_avgCharWidth = widthForGlyph(xGlyph); 164 } 165 } 166 } 167 168 if (int unitsPerEm = face->getUnitsPerEm()) 169 m_fontMetrics.setUnitsPerEm(unitsPerEm); 170 } 171 172 void SimpleFontData::platformCharWidthInit() 173 { 174 // charwidths are set in platformInit. 175 } 176 177 void SimpleFontData::platformDestroy() 178 { 179 } 180 181 PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const 182 { 183 const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor); 184 return SimpleFontData::create(FontPlatformData(m_platformData, scaledSize), isCustomFont() ? CustomFontData::create(false) : 0); 185 } 186 187 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const 188 { 189 SkPaint paint; 190 static const unsigned maxBufferCount = 64; 191 uint16_t glyphs[maxBufferCount]; 192 193 m_platformData.setupPaint(&paint); 194 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 195 196 while (length > 0) { 197 int n = SkMin32(length, SK_ARRAY_COUNT(glyphs)); 198 199 // textToGlyphs takes a byte count so we double the character count. 200 int count = paint.textToGlyphs(characters, n * 2, glyphs); 201 for (int i = 0; i < count; i++) { 202 if (!glyphs[i]) 203 return false; // missing glyph 204 } 205 206 characters += n; 207 length -= n; 208 } 209 210 return true; 211 } 212 213 void SimpleFontData::determinePitch() 214 { 215 m_treatAsFixedPitch = platformData().isFixedPitch(); 216 } 217 218 static inline void getSkiaBoundsForGlyph(SkPaint& paint, Glyph glyph, SkRect& bounds) 219 { 220 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 221 222 SkPath path; 223 paint.getTextPath(&glyph, sizeof(glyph), 0, 0, &path); 224 bounds = path.getBounds(); 225 226 // FIXME(eae): getBounds currently returns an empty rect for bitmap 227 // fonts so fall back on the old behavior. Once fixed in Skia this 228 // fallback can go away. 229 if (bounds.isEmpty()) 230 paint.measureText(&glyph, 2, &bounds); 231 232 if (!paint.isSubpixelText()) { 233 SkIRect ir; 234 bounds.round(&ir); 235 bounds.set(ir); 236 } 237 } 238 239 FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const 240 { 241 if (!m_platformData.size()) 242 return FloatRect(); 243 244 SkASSERT(sizeof(glyph) == 2); // compile-time assert 245 246 SkPaint paint; 247 m_platformData.setupPaint(&paint); 248 249 SkRect bounds; 250 getSkiaBoundsForGlyph(paint, glyph, bounds); 251 return FloatRect(bounds); 252 } 253 254 float SimpleFontData::platformWidthForGlyph(Glyph glyph) const 255 { 256 if (!m_platformData.size()) 257 return 0; 258 259 SkASSERT(sizeof(glyph) == 2); // compile-time assert 260 261 SkPaint paint; 262 263 m_platformData.setupPaint(&paint); 264 265 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 266 SkScalar width = paint.measureText(&glyph, 2); 267 if (!paint.isSubpixelText()) 268 width = SkScalarRound(width); 269 return SkScalarToFloat(width); 270 } 271 272 #if USE(HARFBUZZ) 273 bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const 274 { 275 if (!m_combiningCharacterSequenceSupport) 276 m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>); 277 278 WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); 279 if (!addResult.isNewEntry) 280 return addResult.iterator->value; 281 282 UErrorCode error = U_ZERO_ERROR; 283 Vector<UChar, 4> normalizedCharacters(length); 284 int32_t normalizedLength = unorm_normalize(characters, length, UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], length, &error); 285 // Can't render if we have an error or no composition occurred. 286 if (U_FAILURE(error) || (static_cast<size_t>(normalizedLength) == length)) 287 return false; 288 289 SkPaint paint; 290 m_platformData.setupPaint(&paint); 291 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 292 if (paint.textToGlyphs(&normalizedCharacters[0], normalizedLength * 2, 0)) { 293 addResult.iterator->value = true; 294 return true; 295 } 296 return false; 297 } 298 #endif 299 300 } // namespace WebCore 301