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 "core/css/CSSFontFace.h"
     30 #include "RuntimeEnabledFeatures.h"
     31 #include "core/platform/graphics/FontDescription.h"
     32 #include "core/platform/graphics/SegmentedFontData.h"
     33 #include "core/platform/graphics/SimpleFontData.h"
     34 
     35 namespace WebCore {
     36 
     37 CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector)
     38     : m_fontSelector(fontSelector)
     39 {
     40 }
     41 
     42 CSSSegmentedFontFace::~CSSSegmentedFontFace()
     43 {
     44     pruneTable();
     45     unsigned size = m_fontFaces.size();
     46     for (unsigned i = 0; i < size; i++)
     47         m_fontFaces[i]->removedFromSegmentedFontFace(this);
     48 }
     49 
     50 void CSSSegmentedFontFace::pruneTable()
     51 {
     52     // Make sure the glyph page tree prunes out all uses of this custom font.
     53     if (m_fontDataTable.isEmpty())
     54         return;
     55 
     56     m_fontDataTable.clear();
     57 }
     58 
     59 bool CSSSegmentedFontFace::isValid() const
     60 {
     61     // Valid if at least one font face is valid.
     62     unsigned size = m_fontFaces.size();
     63     for (unsigned i = 0; i < size; i++) {
     64         if (m_fontFaces[i]->isValid())
     65             return true;
     66     }
     67     return false;
     68 }
     69 
     70 void CSSSegmentedFontFace::fontLoaded(CSSFontFace*)
     71 {
     72     pruneTable();
     73 
     74     if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && !isLoading()) {
     75         Vector<RefPtr<LoadFontCallback> > callbacks;
     76         m_callbacks.swap(callbacks);
     77         for (size_t index = 0; index < callbacks.size(); ++index) {
     78             if (checkFont())
     79                 callbacks[index]->notifyLoaded(this);
     80             else
     81                 callbacks[index]->notifyError(this);
     82         }
     83     }
     84 }
     85 
     86 void CSSSegmentedFontFace::appendFontFace(PassRefPtr<CSSFontFace> fontFace)
     87 {
     88     pruneTable();
     89     fontFace->addedToSegmentedFontFace(this);
     90     m_fontFaces.append(fontFace);
     91 }
     92 
     93 static void appendFontDataWithInvalidUnicodeRangeIfLoading(SegmentedFontData* newFontData, PassRefPtr<SimpleFontData> prpFaceFontData, const Vector<CSSFontFace::UnicodeRange>& ranges)
     94 {
     95     RefPtr<SimpleFontData> faceFontData = prpFaceFontData;
     96     if (faceFontData->isLoading()) {
     97         newFontData->appendRange(FontDataRange(0, 0, faceFontData));
     98         return;
     99     }
    100 
    101     unsigned numRanges = ranges.size();
    102     if (!numRanges) {
    103         newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData));
    104         return;
    105     }
    106 
    107     for (unsigned j = 0; j < numRanges; ++j)
    108         newFontData->appendRange(FontDataRange(ranges[j].from(), ranges[j].to(), faceFontData));
    109 }
    110 
    111 PassRefPtr<FontData> CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription)
    112 {
    113     if (!isValid())
    114         return 0;
    115 
    116     FontTraitsMask desiredTraitsMask = fontDescription.traitsMask();
    117     unsigned hashKey = ((fontDescription.computedPixelSize() + 1) << (FontTraitsMaskWidth + FontWidthVariantWidth + 1))
    118         | ((fontDescription.orientation() == Vertical ? 1 : 0) << (FontTraitsMaskWidth + FontWidthVariantWidth))
    119         | fontDescription.widthVariant() << FontTraitsMaskWidth
    120         | desiredTraitsMask;
    121 
    122     RefPtr<SegmentedFontData>& fontData = m_fontDataTable.add(hashKey, 0).iterator->value;
    123     if (fontData && fontData->numRanges())
    124         return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has.
    125 
    126     if (!fontData)
    127         fontData = SegmentedFontData::create();
    128 
    129     unsigned size = m_fontFaces.size();
    130     for (unsigned i = 0; i < size; i++) {
    131         if (!m_fontFaces[i]->isValid())
    132             continue;
    133         FontTraitsMask traitsMask = m_fontFaces[i]->traitsMask();
    134         bool syntheticBold = !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask));
    135         bool syntheticItalic = !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask);
    136         if (RefPtr<SimpleFontData> faceFontData = m_fontFaces[i]->getFontData(fontDescription, syntheticBold, syntheticItalic)) {
    137             ASSERT(!faceFontData->isSegmented());
    138             appendFontDataWithInvalidUnicodeRangeIfLoading(fontData.get(), faceFontData.release(), m_fontFaces[i]->ranges());
    139         }
    140     }
    141     if (fontData->numRanges())
    142         return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has.
    143 
    144     return 0;
    145 }
    146 
    147 bool CSSSegmentedFontFace::isLoading() const
    148 {
    149     unsigned size = m_fontFaces.size();
    150     for (unsigned i = 0; i < size; i++) {
    151         if (m_fontFaces[i]->loadState() == CSSFontFace::Loading)
    152             return true;
    153     }
    154     return false;
    155 }
    156 
    157 bool CSSSegmentedFontFace::checkFont() const
    158 {
    159     unsigned size = m_fontFaces.size();
    160     for (unsigned i = 0; i < size; i++) {
    161         if (m_fontFaces[i]->loadState() != CSSFontFace::Loaded)
    162             return false;
    163     }
    164     return true;
    165 }
    166 
    167 void CSSSegmentedFontFace::loadFont(const FontDescription& fontDescription, PassRefPtr<LoadFontCallback> callback)
    168 {
    169     getFontData(fontDescription); // Kick off the load.
    170 
    171     if (callback) {
    172         if (isLoading())
    173             m_callbacks.append(callback);
    174         else if (checkFont())
    175             callback->notifyLoaded(this);
    176         else
    177             callback->notifyError(this);
    178     }
    179 }
    180 
    181 }
    182