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