1/* 2 * Copyright (C) 2006 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 4 * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> 5 * Copyright (C) 2007 Holger Hans Peter Freyther 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 18 * its contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include "config.h" 34#include "SimpleFontData.h" 35 36#include "FloatConversion.h" 37#include "FloatRect.h" 38#include "Font.h" 39#include "FontCache.h" 40#include "FontDescription.h" 41#include "GlyphBuffer.h" 42#include "OpenTypeTypes.h" 43#include "UTF16UChar32Iterator.h" 44#include <cairo-ft.h> 45#include <cairo.h> 46#include <fontconfig/fcfreetype.h> 47#include <ft2build.h> 48#include FT_TRUETYPE_TABLES_H 49#include FT_TRUETYPE_TAGS_H 50#include <unicode/normlzr.h> 51#include <wtf/MathExtras.h> 52 53namespace WebCore { 54 55void SimpleFontData::platformInit() 56{ 57 if (!m_platformData.m_size) 58 return; 59 60 ASSERT(m_platformData.scaledFont()); 61 cairo_font_extents_t fontExtents; 62 cairo_scaled_font_extents(m_platformData.scaledFont(), &fontExtents); 63 64 float ascent = narrowPrecisionToFloat(fontExtents.ascent); 65 float descent = narrowPrecisionToFloat(fontExtents.descent); 66 float lineGap = narrowPrecisionToFloat(fontExtents.height - fontExtents.ascent - fontExtents.descent); 67 68 m_fontMetrics.setAscent(ascent); 69 m_fontMetrics.setDescent(descent); 70 71#if PLATFORM(EFL) 72 m_fontMetrics.setLineSpacing(ascent + descent + lineGap); 73#else 74 // Match CoreGraphics metrics. 75 m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); 76#endif 77 m_fontMetrics.setLineGap(lineGap); 78 79 cairo_text_extents_t textExtents; 80 cairo_scaled_font_text_extents(m_platformData.scaledFont(), "x", &textExtents); 81 m_fontMetrics.setXHeight(narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.height : textExtents.width)); 82 83 cairo_scaled_font_text_extents(m_platformData.scaledFont(), " ", &textExtents); 84 m_spaceWidth = narrowPrecisionToFloat((platformData().orientation() == Horizontal) ? textExtents.x_advance : -textExtents.y_advance); 85 86 if ((platformData().orientation() == Vertical) && !isTextOrientationFallback()) { 87 FT_Face freeTypeFace = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); 88 m_fontMetrics.setUnitsPerEm(freeTypeFace->units_per_EM); 89 cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); 90 } 91 92 m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; 93} 94 95void SimpleFontData::platformCharWidthInit() 96{ 97 m_avgCharWidth = 0.f; 98 m_maxCharWidth = 0.f; 99 initCharWidths(); 100} 101 102void SimpleFontData::platformDestroy() 103{ 104} 105 106PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const 107{ 108 ASSERT(m_platformData.scaledFont()); 109 return SimpleFontData::create(FontPlatformData(cairo_scaled_font_get_font_face(m_platformData.scaledFont()), 110 scaleFactor * fontDescription.computedSize(), 111 m_platformData.syntheticBold(), 112 m_platformData.syntheticOblique(), 113 fontDescription.orientation()), 114 isCustomFont(), false); 115} 116 117bool SimpleFontData::containsCharacters(const UChar* characters, int bufferLength) const 118{ 119 ASSERT(m_platformData.scaledFont()); 120 FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); 121 if (!face) 122 return false; 123 124 UTF16UChar32Iterator iterator(characters, bufferLength); 125 UChar32 character = iterator.next(); 126 while (character != iterator.end()) { 127 if (!FcFreeTypeCharIndex(face, character)) { 128 cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); 129 return false; 130 } 131 character = iterator.next(); 132 } 133 134 cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); 135 return true; 136} 137 138void SimpleFontData::determinePitch() 139{ 140 m_treatAsFixedPitch = m_platformData.isFixedPitch(); 141} 142 143FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const 144{ 145 if (!m_platformData.size()) 146 return FloatRect(); 147 148 cairo_glyph_t cglyph = { glyph, 0, 0 }; 149 cairo_text_extents_t extents; 150 cairo_scaled_font_glyph_extents(m_platformData.scaledFont(), &cglyph, 1, &extents); 151 152 if (cairo_scaled_font_status(m_platformData.scaledFont()) == CAIRO_STATUS_SUCCESS) 153 return FloatRect(extents.x_bearing, extents.y_bearing, extents.width, extents.height); 154 155 return FloatRect(); 156} 157 158float SimpleFontData::platformWidthForGlyph(Glyph glyph) const 159{ 160 if (!m_platformData.size()) 161 return 0; 162 163 if (cairo_scaled_font_status(m_platformData.scaledFont()) != CAIRO_STATUS_SUCCESS) 164 return m_spaceWidth; 165 166 cairo_glyph_t cairoGlyph = { glyph, 0, 0 }; 167 cairo_text_extents_t extents; 168 cairo_scaled_font_glyph_extents(m_platformData.scaledFont(), &cairoGlyph, 1, &extents); 169 float width = platformData().orientation() == Horizontal ? extents.x_advance : -extents.y_advance; 170 return width ? width : m_spaceWidth; 171} 172 173#if USE(HARFBUZZ) 174bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const 175{ 176 if (!m_combiningCharacterSequenceSupport) 177 m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>); 178 179 WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); 180 if (!addResult.isNewEntry) 181 return addResult.iterator->value; 182 183 UErrorCode error = U_ZERO_ERROR; 184 Vector<UChar, 4> normalizedCharacters(length); 185 int32_t normalizedLength = unorm_normalize(characters, length, UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], length, &error); 186 // Can't render if we have an error or no composition occurred. 187 if (U_FAILURE(error) || (static_cast<size_t>(normalizedLength) == length)) 188 return false; 189 190 FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.scaledFont()); 191 if (!face) 192 return false; 193 194 if (FcFreeTypeCharIndex(face, normalizedCharacters[0])) 195 addResult.iterator->value = true; 196 197 cairo_ft_scaled_font_unlock_face(m_platformData.scaledFont()); 198 return addResult.iterator->value; 199} 200#endif 201 202} 203