1/*
2 * Copyright (C) 2006 Apple Computer, 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
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "FontFallbackList.h"
31
32#include "Font.h"
33#include "FontCache.h"
34#include "SegmentedFontData.h"
35
36namespace WebCore {
37
38FontFallbackList::FontFallbackList()
39    : m_pageZero(0)
40    , m_cachedPrimarySimpleFontData(0)
41    , m_fontSelector(0)
42    , m_familyIndex(0)
43    , m_pitch(UnknownPitch)
44    , m_loadingCustomFonts(false)
45    , m_generation(fontCache()->generation())
46{
47}
48
49void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
50{
51    releaseFontData();
52    m_fontList.clear();
53    m_pageZero = 0;
54    m_pages.clear();
55    m_cachedPrimarySimpleFontData = 0;
56    m_familyIndex = 0;
57    m_pitch = UnknownPitch;
58    m_loadingCustomFonts = false;
59    m_fontSelector = fontSelector;
60    m_generation = fontCache()->generation();
61}
62
63void FontFallbackList::releaseFontData()
64{
65    unsigned numFonts = m_fontList.size();
66    for (unsigned i = 0; i < numFonts; ++i) {
67        if (!m_fontList[i].second) {
68            ASSERT(!m_fontList[i].first->isSegmented());
69            fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first));
70        }
71    }
72}
73
74void FontFallbackList::determinePitch(const Font* font) const
75{
76    const FontData* fontData = primaryFontData(font);
77    if (!fontData->isSegmented())
78        m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
79    else {
80        const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
81        unsigned numRanges = segmentedFontData->numRanges();
82        if (numRanges == 1)
83            m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
84        else
85            m_pitch = VariablePitch;
86    }
87}
88
89const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realizedFontIndex) const
90{
91    if (realizedFontIndex < m_fontList.size())
92        return m_fontList[realizedFontIndex].first; // This fallback font is already in our list.
93
94    // Make sure we're not passing in some crazy value here.
95    ASSERT(realizedFontIndex == m_fontList.size());
96
97    if (m_familyIndex == cAllFamiliesScanned)
98        return 0;
99
100    // Ask the font cache for the font data.
101    // We are obtaining this font for the first time.  We keep track of the families we've looked at before
102    // in |m_familyIndex|, so that we never scan the same spot in the list twice.  getFontData will adjust our
103    // |m_familyIndex| as it scans for the right font to make.
104    ASSERT(fontCache()->generation() == m_generation);
105    const FontData* result = fontCache()->getFontData(*font, m_familyIndex, m_fontSelector.get());
106    if (result) {
107        m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
108        if (result->isLoading())
109            m_loadingCustomFonts = true;
110    }
111    return result;
112}
113
114const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const UChar* characters, int length) const
115{
116    // This method is only called when the primary font does not contain the characters we need.
117    // Begin our search at position 1.
118    unsigned realizedFontIndex = 1;
119    const FontData* fontData = fontDataAt(font, realizedFontIndex);
120    while (fontData && !fontData->containsCharacters(characters, length))
121        fontData = fontDataAt(font, ++realizedFontIndex);
122
123    if (!fontData) {
124        ASSERT(fontCache()->generation() == m_generation);
125        fontData = fontCache()->getFontDataForCharacters(*font, characters, length);
126    }
127
128    return fontData;
129}
130
131void FontFallbackList::setPlatformFont(const FontPlatformData& platformData)
132{
133    m_familyIndex = cAllFamiliesScanned;
134    ASSERT(fontCache()->generation() == m_generation);
135    const FontData* fontData = fontCache()->getCachedFontData(&platformData);
136    m_fontList.append(pair<const FontData*, bool>(fontData, fontData->isCustomFont()));
137}
138
139}
140