6fd5c29e6e209af7dd52604e3f324a1139666d01
[WebKit-https.git] / Source / WebCore / platform / graphics / mac / GlyphPageTreeNodeMac.cpp
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 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
32 #include "CoreGraphicsSPI.h"
33 #include "CoreTextSPI.h"
34 #include "Font.h"
35 #include "SimpleFontData.h"
36 #include "WebCoreSystemInterface.h"
37 #if !PLATFORM(IOS)
38 #include <ApplicationServices/ApplicationServices.h>
39 #endif
40
41 namespace WebCore {
42
43 static bool shouldUseCoreText(const UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
44 {
45     if (fontData->platformData().isCompositeFontReference())
46         return true;
47     if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) {
48         // Ideographs don't have a vertical variant or width variants.
49         for (unsigned i = 0; i < bufferLength; ++i) {
50             if (!Font::isCJKIdeograph(buffer[i]))
51                 return true;
52         }
53     }
54
55     return false;
56 }
57
58 bool GlyphPage::mayUseMixedFontDataWhenFilling(const UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
59 {
60     // FIXME: This could be smarter if the logic currently in GlyphPage::fill() got to make the decision about what kind of GlyphPage to construct.
61     return shouldUseCoreText(buffer, bufferLength, fontData);
62 }
63
64 bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
65 {
66     bool haveGlyphs = false;
67
68     Vector<CGGlyph, 512> glyphs(bufferLength);
69     if (!shouldUseCoreText(buffer, bufferLength, fontData)) {
70         // We pass in either 256 or 512 UTF-16 characters: 256 for U+FFFF and less, 512 (double character surrogates)
71         // for U+10000 and above. It is indeed possible to get back 512 glyphs back from the API, so the glyph buffer
72         // we pass in must be 512. If we get back more than 256 glyphs though we'll ignore all the ones after 256,
73         // this should not happen as the only time we pass in 512 characters is when they are surrogates.
74         CGFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
75         for (unsigned i = 0; i < length; ++i) {
76             if (!glyphs[i])
77                 setGlyphDataForIndex(offset + i, 0, 0);
78             else {
79                 setGlyphDataForIndex(offset + i, glyphs[i], fontData);
80                 haveGlyphs = true;
81             }
82         }
83     } else if (!fontData->platformData().isCompositeFontReference() && ((fontData->platformData().widthVariant() == RegularWidth) ? CTFontGetVerticalGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)
84                : CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength))) {
85         // When buffer consists of surrogate pairs, CTFontGetVerticalGlyphsForCharacters and CTFontGetGlyphsForCharacters
86         // place the glyphs at indices corresponding to the first character of each pair.
87         ASSERT(!(bufferLength % length) && (bufferLength / length == 1 || bufferLength / length == 2));
88         unsigned glyphStep = bufferLength / length;
89         for (unsigned i = 0; i < length; ++i) {
90             if (!glyphs[i * glyphStep])
91                 setGlyphDataForIndex(offset + i, 0, 0);
92             else {
93                 setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], fontData);
94                 haveGlyphs = true;
95             }
96         }
97     } else {
98         // We ask CoreText for possible vertical variant glyphs
99         RetainPtr<CFStringRef> string = adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull));
100         RetainPtr<CFAttributedStringRef> attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal)));
101         RetainPtr<CTLineRef> line = adoptCF(CTLineCreateWithAttributedString(attributedString.get()));
102
103         CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
104         CFIndex runCount = CFArrayGetCount(runArray);
105
106         // Initialize glyph entries
107         for (unsigned index = 0; index < length; ++index)
108             setGlyphDataForIndex(offset + index, 0, 0);
109
110         Vector<CGGlyph, 512> glyphVector;
111         Vector<CFIndex, 512> indexVector;
112         bool done = false;
113
114         RetainPtr<CFTypeRef> fontEqualityObject = fontData->platformData().objectForEqualityCheck();
115
116         for (CFIndex r = 0; r < runCount && !done ; ++r) {
117             // CTLine could map characters over multiple fonts using its own font fallback list.
118             // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
119             CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
120             ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
121
122             CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
123             CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
124             bool gotBaseFont = CFEqual(fontEqualityObject.get(), FontPlatformData::objectForEqualityCheck(runFont).get());
125             if (gotBaseFont || fontData->platformData().isCompositeFontReference()) {
126                 // This run uses the font we want. Extract glyphs.
127                 CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
128                 const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
129                 if (!glyphs) {
130                     glyphVector.resize(glyphCount);
131                     CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
132                     glyphs = glyphVector.data();
133                 }
134                 const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
135                 if (!stringIndices) {
136                     indexVector.resize(glyphCount);
137                     CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
138                     stringIndices = indexVector.data();
139                 }
140
141                 // When buffer consists of surrogate pairs, CTRunGetStringIndicesPtr and CTRunGetStringIndices
142                 // place the glyphs at indices corresponding to the first character of each pair.
143                 ASSERT(!(bufferLength % length) && (bufferLength / length == 1 || bufferLength / length == 2));
144                 unsigned glyphStep = bufferLength / length;
145                 if (gotBaseFont) {
146                     for (CFIndex i = 0; i < glyphCount; ++i) {
147                         if (stringIndices[i] >= static_cast<CFIndex>(bufferLength)) {
148                             done = true;
149                             break;
150                         }
151                         if (glyphs[i]) {
152                             setGlyphDataForIndex(offset + (stringIndices[i] / glyphStep), glyphs[i], fontData);
153                             haveGlyphs = true;
154                         }
155                     }
156 #if !PLATFORM(IOS)
157                 } else {
158                     const SimpleFontData* runSimple = fontData->getCompositeFontReferenceFontData((NSFont *)runFont);
159                     if (runSimple) {
160                         for (CFIndex i = 0; i < glyphCount; ++i) {
161                             if (stringIndices[i] >= static_cast<CFIndex>(bufferLength)) {
162                                 done = true;
163                                 break;
164                             }
165                             if (glyphs[i]) {
166                                 setGlyphDataForIndex(offset + (stringIndices[i] / glyphStep), glyphs[i], runSimple);
167                                 haveGlyphs = true;
168                             }
169                         }
170                     }
171 #endif // !PLATFORM(IOS)
172                 }
173             }
174         }
175     }
176
177     return haveGlyphs;
178 }
179
180 } // namespace WebCore