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 "SimpleFontData.h" 33 34 #include "Font.h" 35 #include "FontCache.h" 36 #include "FloatRect.h" 37 #include "FontDescription.h" 38 #include "Logging.h" 39 #include "VDMXParser.h" 40 41 #include "SkFontHost.h" 42 #include "SkPaint.h" 43 #include "SkTime.h" 44 #include "SkTypeface.h" 45 #include "SkTypes.h" 46 47 namespace WebCore { 48 49 // Smallcaps versions of fonts are 70% the size of the normal font. 50 static const float smallCapsFraction = 0.7f; 51 static const float emphasisMarkFraction = .5; 52 // This is the largest VDMX table which we'll try to load and parse. 53 static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB 54 55 void SimpleFontData::platformInit() 56 { 57 if (!m_platformData.size()) { 58 m_fontMetrics.reset(); 59 m_avgCharWidth = 0; 60 m_maxCharWidth = 0; 61 return; 62 } 63 64 SkPaint paint; 65 SkPaint::FontMetrics metrics; 66 67 m_platformData.setupPaint(&paint); 68 paint.getFontMetrics(&metrics); 69 const SkFontID fontID = m_platformData.uniqueID(); 70 71 static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); 72 int pixelSize = m_platformData.size() + 0.5; 73 int vdmxAscent, vdmxDescent; 74 bool isVDMXValid = false; 75 76 size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag); 77 if (vdmxSize && vdmxSize < maxVDMXTableSize) { 78 uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); 79 if (vdmxTable 80 && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize 81 && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) 82 isVDMXValid = true; 83 fastFree(vdmxTable); 84 } 85 86 float ascent; 87 float descent; 88 89 // Beware those who step here: This code is designed to match Win32 font 90 // metrics *exactly*. 91 if (isVDMXValid) { 92 ascent = vdmxAscent; 93 descent = -vdmxDescent; 94 } else { 95 SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading; 96 ascent = SkScalarRound(-metrics.fAscent); 97 descent = SkScalarRound(height) - ascent; 98 } 99 100 m_fontMetrics.setAscent(ascent); 101 m_fontMetrics.setDescent(descent); 102 103 float xHeight; 104 if (metrics.fXHeight) 105 xHeight = metrics.fXHeight; 106 else { 107 // hack taken from the Windows port 108 xHeight = ascent * 0.56f; 109 } 110 111 float lineGap = SkScalarToFloat(metrics.fLeading); 112 m_fontMetrics.setLineGap(lineGap); 113 m_fontMetrics.setXHeight(xHeight); 114 m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); 115 116 if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { 117 static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); 118 static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); 119 size_t vheaSize = SkFontHost::GetTableSize(fontID, vheaTag); 120 size_t vorgSize = SkFontHost::GetTableSize(fontID, vorgTag); 121 if ((vheaSize > 0) || (vorgSize > 0)) 122 m_hasVerticalGlyphs = true; 123 } 124 125 // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is 126 // calculated for us, but we need to calculate m_maxCharWidth and 127 // m_avgCharWidth in order for text entry widgets to be sized correctly. 128 129 SkScalar xRange = metrics.fXMax - metrics.fXMin; 130 m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); 131 132 if (metrics.fAvgCharWidth) 133 m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); 134 else { 135 m_avgCharWidth = xHeight; 136 137 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 138 139 if (glyphPageZero) { 140 static const UChar32 x_char = 'x'; 141 const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph; 142 143 if (xGlyph) 144 m_avgCharWidth = widthForGlyph(xGlyph); 145 } 146 } 147 } 148 149 void SimpleFontData::platformCharWidthInit() 150 { 151 // charwidths are set in platformInit. 152 } 153 154 void SimpleFontData::platformDestroy() 155 { 156 } 157 158 SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const 159 { 160 const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor); 161 return new SimpleFontData(FontPlatformData(m_platformData, scaledSize), isCustomFont(), false); 162 } 163 164 SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const 165 { 166 if (!m_derivedFontData) 167 m_derivedFontData = DerivedFontData::create(isCustomFont()); 168 if (!m_derivedFontData->smallCaps) 169 m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFraction); 170 171 return m_derivedFontData->smallCaps.get(); 172 } 173 174 SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const 175 { 176 if (!m_derivedFontData) 177 m_derivedFontData = DerivedFontData::create(isCustomFont()); 178 if (!m_derivedFontData->emphasisMark) 179 m_derivedFontData->emphasisMark = scaledFontData(fontDescription, emphasisMarkFraction); 180 181 return m_derivedFontData->emphasisMark.get(); 182 } 183 184 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const 185 { 186 SkPaint paint; 187 static const unsigned maxBufferCount = 64; 188 uint16_t glyphs[maxBufferCount]; 189 190 m_platformData.setupPaint(&paint); 191 paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 192 193 while (length > 0) { 194 int n = SkMin32(length, SK_ARRAY_COUNT(glyphs)); 195 196 // textToGlyphs takes a byte count so we double the character count. 197 int count = paint.textToGlyphs(characters, n * 2, glyphs); 198 for (int i = 0; i < count; i++) { 199 if (0 == glyphs[i]) 200 return false; // missing glyph 201 } 202 203 characters += n; 204 length -= n; 205 } 206 207 return true; 208 } 209 210 void SimpleFontData::determinePitch() 211 { 212 m_treatAsFixedPitch = platformData().isFixedPitch(); 213 } 214 215 FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const 216 { 217 return FloatRect(); 218 } 219 220 float SimpleFontData::platformWidthForGlyph(Glyph glyph) const 221 { 222 if (!m_platformData.size()) 223 return 0; 224 225 SkASSERT(sizeof(glyph) == 2); // compile-time assert 226 227 SkPaint paint; 228 229 m_platformData.setupPaint(&paint); 230 231 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 232 SkScalar width = paint.measureText(&glyph, 2); 233 234 // Though WebKit supports non-integral advances, Skia only supports them 235 // for "subpixel" (distinct from LCD subpixel antialiasing) text, which 236 // we don't use. 237 return round(SkScalarToFloat(width)); 238 } 239 240 } // namespace WebCore 241