Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2008 Apple 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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/css/CSSSegmentedFontFace.h"
     28 
     29 #include "RuntimeEnabledFeatures.h"
     30 #include "core/css/CSSFontFace.h"
     31 #include "platform/fonts/FontCache.h"
     32 #include "platform/fonts/FontDescription.h"
     33 #include "platform/fonts/SegmentedFontData.h"
     34 #include "platform/fonts/SimpleFontData.h"
     35 
     36 namespace WebCore {
     37 
     38 CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector, FontTraitsMask traitsMask)
     39     : m_fontSelector(fontSelector)
     40     , m_traitsMask(traitsMask)
     41 {
     42 }
     43 
     44 CSSSegmentedFontFace::~CSSSegmentedFontFace()
     45 {
     46     pruneTable();
     47     unsigned size = m_fontFaces.size();
     48     for (unsigned i = 0; i < size; i++)
     49         m_fontFaces[i]->clearSegmentedFontFace();
     50 }
     51 
     52 void CSSSegmentedFontFace::pruneTable()
     53 {
     54     // Make sure the glyph page tree prunes out all uses of this custom font.
     55     if (m_fontDataTable.isEmpty())
     56         return;
     57 
     58     m_fontDataTable.clear();
     59 }
     60 
     61 bool CSSSegmentedFontFace::isValid() const
     62 {
     63     // Valid if at least one font face is valid.
     64     unsigned size = m_fontFaces.size();
     65     for (unsigned i = 0; i < size; i++) {
     66         if (m_fontFaces[i]->isValid())
     67             return true;
     68     }
     69     return false;
     70 }
     71 
     72 void CSSSegmentedFontFace::fontLoaded(CSSFontFace*)
     73 {
     74     pruneTable();
     75 
     76     if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && !isLoading()) {
     77         Vector<RefPtr<LoadFontCallback> > callbacks;
     78         m_callbacks.swap(callbacks);
     79         for (size_t index = 0; index < callbacks.size(); ++index) {
     80             if (isLoaded())
     81                 callbacks[index]->notifyLoaded(this);
     82             else
     83                 callbacks[index]->notifyError(this);
     84         }
     85     }
     86 }
     87 
     88 void CSSSegmentedFontFace::appendFontFace(PassRefPtr<CSSFontFace> fontFace)
     89 {
     90     pruneTable();
     91     fontFace->setSegmentedFontFace(this);
     92     m_fontFaces.append(fontFace);
     93 }
     94 
     95 void CSSSegmentedFontFace::removeFontFace(PassRefPtr<CSSFontFace> fontFace)
     96 {
     97     size_t index = m_fontFaces.find(fontFace);
     98     if (index != kNotFound) {
     99         pruneTable();
    100         m_fontFaces.remove(index);
    101         fontFace->clearSegmentedFontFace();
    102     }
    103 }
    104 
    105 static void appendFontData(SegmentedFontData* newFontData, PassRefPtr<SimpleFontData> prpFaceFontData, const CSSFontFace::UnicodeRangeSet& ranges)
    106 {
    107     RefPtr<SimpleFontData> faceFontData = prpFaceFontData;
    108     unsigned numRanges = ranges.size();
    109     if (!numRanges) {
    110         newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData));
    111         return;
    112     }
    113 
    114     for (unsigned j = 0; j < numRanges; ++j)
    115         newFontData->appendRange(FontDataRange(ranges.rangeAt(j).from(), ranges.rangeAt(j).to(), faceFontData));
    116 }
    117 
    118 PassRefPtr<FontData> CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription)
    119 {
    120     if (!isValid())
    121         return 0;
    122 
    123     FontTraitsMask desiredTraitsMask = fontDescription.traitsMask();
    124     AtomicString emptyFontFamily = "";
    125     FontCacheKey key = fontDescription.cacheKey(emptyFontFamily, desiredTraitsMask);
    126 
    127     RefPtr<SegmentedFontData>& fontData = m_fontDataTable.add(key.hash(), 0).iterator->value;
    128     if (fontData && fontData->numRanges())
    129         return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has.
    130 
    131     if (!fontData)
    132         fontData = SegmentedFontData::create();
    133 
    134     FontDescription requestedFontDescription(fontDescription);
    135     requestedFontDescription.setTraitsMask(m_traitsMask);
    136     requestedFontDescription.setSyntheticBold(!(m_traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)));
    137     requestedFontDescription.setSyntheticItalic(!(m_traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask));
    138 
    139     for (int i = m_fontFaces.size() - 1; i >= 0; --i) {
    140         if (!m_fontFaces[i]->isValid())
    141             continue;
    142         if (RefPtr<SimpleFontData> faceFontData = m_fontFaces[i]->getFontData(requestedFontDescription)) {
    143             ASSERT(!faceFontData->isSegmented());
    144 #if ENABLE(SVG_FONTS)
    145             // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable
    146             // of small-caps synthesis and just ignore the font face.
    147             if (faceFontData->isSVGFont() && (desiredTraitsMask & FontVariantSmallCapsMask) && !(m_traitsMask & FontVariantSmallCapsMask))
    148                 continue;
    149 #endif
    150             appendFontData(fontData.get(), faceFontData.release(), m_fontFaces[i]->ranges());
    151         }
    152     }
    153     if (fontData->numRanges())
    154         return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has.
    155 
    156     return 0;
    157 }
    158 
    159 bool CSSSegmentedFontFace::isLoading() const
    160 {
    161     unsigned size = m_fontFaces.size();
    162     for (unsigned i = 0; i < size; i++) {
    163         if (m_fontFaces[i]->loadStatus() == FontFace::Loading)
    164             return true;
    165     }
    166     return false;
    167 }
    168 
    169 bool CSSSegmentedFontFace::isLoaded() const
    170 {
    171     unsigned size = m_fontFaces.size();
    172     for (unsigned i = 0; i < size; i++) {
    173         if (m_fontFaces[i]->loadStatus() != FontFace::Loaded)
    174             return false;
    175     }
    176     return true;
    177 }
    178 
    179 void CSSSegmentedFontFace::willUseFontData(const FontDescription& fontDescription)
    180 {
    181     unsigned size = m_fontFaces.size();
    182     for (unsigned i = 0; i < size; i++)
    183         m_fontFaces[i]->willUseFontData(fontDescription);
    184 }
    185 
    186 bool CSSSegmentedFontFace::checkFont(const String& text) const
    187 {
    188     unsigned size = m_fontFaces.size();
    189     for (unsigned i = 0; i < size; i++) {
    190         if (m_fontFaces[i]->loadStatus() != FontFace::Loaded && m_fontFaces[i]->ranges().intersectsWith(text))
    191             return false;
    192     }
    193     return true;
    194 }
    195 
    196 void CSSSegmentedFontFace::loadFont(const FontDescription& fontDescription, const String& text, PassRefPtr<LoadFontCallback> callback)
    197 {
    198     unsigned size = m_fontFaces.size();
    199     for (unsigned i = 0; i < size; i++) {
    200         if (m_fontFaces[i]->loadStatus() == FontFace::Unloaded && m_fontFaces[i]->ranges().intersectsWith(text)) {
    201             RefPtr<SimpleFontData> fontData = m_fontFaces[i]->getFontData(fontDescription);
    202             if (fontData->customFontData())
    203                 fontData->customFontData()->beginLoadIfNeeded();
    204         }
    205     }
    206 
    207     if (callback) {
    208         if (isLoading())
    209             m_callbacks.append(callback);
    210         else if (isLoaded())
    211             callback->notifyLoaded(this);
    212         else
    213             callback->notifyError(this);
    214     }
    215 }
    216 
    217 Vector<RefPtr<FontFace> > CSSSegmentedFontFace::fontFaces(const String& text) const
    218 {
    219     Vector<RefPtr<FontFace> > fontFaces;
    220     unsigned size = m_fontFaces.size();
    221     for (unsigned i = 0; i < size; i++) {
    222         if (m_fontFaces[i]->ranges().intersectsWith(text))
    223             fontFaces.append(m_fontFaces[i]->fontFace());
    224     }
    225     return fontFaces;
    226 }
    227 
    228 }
    229