1 /* 2 * Copyright (C) 2006, 2007 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 * 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 "GlyphPageTreeNode.h" 31 #include "Font.h" 32 33 #include "SimpleFontData.h" 34 #include "WebCoreSystemInterface.h" 35 #include <ApplicationServices/ApplicationServices.h> 36 37 namespace WebCore { 38 39 #ifndef BUILDING_ON_TIGER 40 static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) 41 { 42 if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) { 43 // Ideographs don't have a vertical variant or width variants. 44 for (unsigned i = 0; i < bufferLength; ++i) { 45 if (!Font::isCJKIdeograph(buffer[i])) 46 return true; 47 } 48 } 49 50 return false; 51 } 52 #endif 53 54 bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) 55 { 56 bool haveGlyphs = false; 57 58 #ifndef BUILDING_ON_TIGER 59 if (!shouldUseCoreText(buffer, bufferLength, fontData)) { 60 Vector<CGGlyph, 512> glyphs(bufferLength); 61 wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength); 62 for (unsigned i = 0; i < length; ++i) { 63 if (!glyphs[i]) 64 setGlyphDataForIndex(offset + i, 0, 0); 65 else { 66 setGlyphDataForIndex(offset + i, glyphs[i], fontData); 67 haveGlyphs = true; 68 } 69 } 70 } else { 71 // We ask CoreText for possible vertical variant glyphs 72 RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); 73 RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal))); 74 RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); 75 76 CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); 77 CFIndex runCount = CFArrayGetCount(runArray); 78 79 // Initialize glyph entries 80 for (unsigned index = 0; index < length; ++index) 81 setGlyphDataForIndex(offset + index, 0, 0); 82 83 Vector<CGGlyph, 512> glyphVector; 84 Vector<CFIndex, 512> indexVector; 85 bool done = false; 86 87 // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may 88 // be non-CFEqual to fontData->platformData().cgFont(). 89 RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0)); 90 91 for (CFIndex r = 0; r < runCount && !done ; ++r) { 92 // CTLine could map characters over multiple fonts using its own font fallback list. 93 // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont(). 94 CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); 95 ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); 96 97 CFDictionaryRef attributes = CTRunGetAttributes(ctRun); 98 CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName)); 99 RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0)); 100 // Use CGFont here as CFEqual for CTFont counts all attributes for font. 101 if (CFEqual(cgFont.get(), runCGFont.get())) { 102 // This run uses the font we want. Extract glyphs. 103 CFIndex glyphCount = CTRunGetGlyphCount(ctRun); 104 const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun); 105 if (!glyphs) { 106 glyphVector.resize(glyphCount); 107 CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data()); 108 glyphs = glyphVector.data(); 109 } 110 const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun); 111 if (!stringIndices) { 112 indexVector.resize(glyphCount); 113 CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data()); 114 stringIndices = indexVector.data(); 115 } 116 117 for (CFIndex i = 0; i < glyphCount; ++i) { 118 if (stringIndices[i] >= static_cast<CFIndex>(length)) { 119 done = true; 120 break; 121 } 122 if (glyphs[i]) { 123 setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData); 124 haveGlyphs = true; 125 } 126 } 127 } 128 } 129 } 130 #else 131 // Use an array of long so we get good enough alignment. 132 long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)]; 133 134 OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector); 135 if (status != noErr) 136 // This should never happen, perhaps indicates a bad font! If it does the 137 // font substitution code will find an alternate font. 138 return false; 139 140 wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector); 141 142 unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector); 143 if (numGlyphs != length) { 144 // This should never happen, perhaps indicates a bad font? 145 // If it does happen, the font substitution code will find an alternate font. 146 wkClearGlyphVector(&glyphVector); 147 return false; 148 } 149 150 ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector); 151 for (unsigned i = 0; i < length; i++) { 152 Glyph glyph = glyphRecord->glyphID; 153 if (!glyph) 154 setGlyphDataForIndex(offset + i, 0, 0); 155 else { 156 setGlyphDataForIndex(offset + i, glyph, fontData); 157 haveGlyphs = true; 158 } 159 glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector)); 160 } 161 wkClearGlyphVector(&glyphVector); 162 #endif 163 164 return haveGlyphs; 165 } 166 167 } // namespace WebCore 168