1/*
2 * Copyright (C) 2005, 2008 Apple Computer, Inc.  All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 *     its contributors may be used to endorse or promote products derived
16 *     from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "SimpleFontData.h"
32
33#include "Font.h"
34#include "FontCache.h"
35
36#if ENABLE(SVG_FONTS)
37#include "SVGFontData.h"
38#include "SVGFontElement.h"
39#include "SVGFontFaceElement.h"
40#include "SVGGlyphElement.h"
41#endif
42
43#include <wtf/MathExtras.h>
44#include <wtf/UnusedParam.h>
45
46using namespace std;
47
48namespace WebCore {
49
50SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData)
51    : m_maxCharWidth(-1)
52    , m_avgCharWidth(-1)
53    , m_unitsPerEm(defaultUnitsPerEm)
54    , m_platformData(f)
55    , m_treatAsFixedPitch(false)
56#if ENABLE(SVG_FONTS)
57    , m_svgFontData(svgFontData)
58#endif
59    , m_isCustomFont(customFont)
60    , m_isLoading(loading)
61    , m_smallCapsFontData(0)
62{
63#if !ENABLE(SVG_FONTS)
64    UNUSED_PARAM(svgFontData);
65#else
66    if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) {
67        m_unitsPerEm = svgFontFaceElement->unitsPerEm();
68
69        double scale = f.size();
70        if (m_unitsPerEm)
71            scale /= m_unitsPerEm;
72
73        m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale);
74        m_descent = static_cast<int>(svgFontFaceElement->descent() * scale);
75        m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale);
76        m_lineGap = 0.1f * f.size();
77        m_lineSpacing = m_ascent + m_descent + m_lineGap;
78
79        SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
80
81        Vector<SVGGlyphIdentifier> spaceGlyphs;
82        associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
83        m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale);
84
85        Vector<SVGGlyphIdentifier> numeralZeroGlyphs;
86        associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
87        m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale);
88
89        Vector<SVGGlyphIdentifier> letterWGlyphs;
90        associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs);
91        m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale);
92
93        // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above?
94        m_spaceGlyph = 0;
95        determinePitch();
96        m_adjustedSpaceWidth = roundf(m_spaceWidth);
97        m_missingGlyphData.fontData = this;
98        m_missingGlyphData.glyph = 0;
99        return;
100    }
101#endif
102
103    platformInit();
104    platformGlyphInit();
105    platformCharWidthInit();
106}
107
108#if !PLATFORM(QT)
109// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
110void SimpleFontData::initCharWidths()
111{
112    GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
113
114    // Treat the width of a '0' as the avgCharWidth.
115    if (m_avgCharWidth <= 0.f && glyphPageZero) {
116        static const UChar32 digitZeroChar = '0';
117        Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph;
118        if (digitZeroGlyph)
119            m_avgCharWidth = widthForGlyph(digitZeroGlyph);
120    }
121
122    // If we can't retrieve the width of a '0', fall back to the x height.
123    if (m_avgCharWidth <= 0.f)
124        m_avgCharWidth = m_xHeight;
125
126    if (m_maxCharWidth <= 0.f)
127        m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent);
128}
129
130void SimpleFontData::platformGlyphInit()
131{
132    GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
133    if (!glyphPageZero) {
134        LOG_ERROR("Failed to get glyph page zero.");
135        m_spaceGlyph = 0;
136        m_spaceWidth = 0;
137        m_adjustedSpaceWidth = 0;
138        determinePitch();
139        m_missingGlyphData.fontData = this;
140        m_missingGlyphData.glyph = 0;
141        return;
142    }
143
144    // Nasty hack to determine if we should round or ceil space widths.
145    // If the font is monospace or fake monospace we ceil to ensure that
146    // every character and the space are the same width.  Otherwise we round.
147    m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
148    float width = widthForGlyph(m_spaceGlyph);
149    m_spaceWidth = width;
150    determinePitch();
151    m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
152
153    // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
154    // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
155    // See <http://bugs.webkit.org/show_bug.cgi?id=13178>
156    // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
157    // are mapped to the ZERO WIDTH SPACE glyph.
158    Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
159    if (zeroWidthSpaceGlyph) {
160        if (zeroWidthSpaceGlyph != m_spaceGlyph)
161            m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0);
162        else
163            LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden.");
164    }
165
166    m_missingGlyphData.fontData = this;
167    m_missingGlyphData.glyph = 0;
168}
169#endif
170
171SimpleFontData::~SimpleFontData()
172{
173#if ENABLE(SVG_FONTS)
174    if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
175#endif
176        platformDestroy();
177
178    if (!isCustomFont()) {
179        if (m_smallCapsFontData)
180            fontCache()->releaseFontData(m_smallCapsFontData);
181        GlyphPageTreeNode::pruneTreeFontData(this);
182    }
183}
184
185const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
186{
187    return this;
188}
189
190bool SimpleFontData::isSegmented() const
191{
192    return false;
193}
194
195#ifndef NDEBUG
196String SimpleFontData::description() const
197{
198    if (isSVGFont())
199        return "[SVG font]";
200    if (isCustomFont())
201        return "[custom font]";
202
203    return platformData().description();
204}
205#endif
206
207} // namespace WebCore
208