3e9962b7e30ba8dd9e0dfcf9b016a4e7204bb9bd
[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         // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may
115         // be non-CFEqual to fontData->platformData().cgFont().
116         RetainPtr<CGFontRef> cgFont = adoptCF(CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0));
117
118         for (CFIndex r = 0; r < runCount && !done ; ++r) {
119             // CTLine could map characters over multiple fonts using its own font fallback list.
120             // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont().
121             CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
122             ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
123
124             CFDictionaryRef attributes = CTRunGetAttributes(ctRun);
125             CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName));
126             RetainPtr<CGFontRef> runCGFont = adoptCF(CTFontCopyGraphicsFont(runFont, 0));
127             // Use CGFont here as CFEqual for CTFont counts all attributes for font.
128             bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get());
129             if (gotBaseFont || fontData->platformData().isCompositeFontReference()) {
130                 // This run uses the font we want. Extract glyphs.
131                 CFIndex glyphCount = CTRunGetGlyphCount(ctRun);
132                 const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun);
133                 if (!glyphs) {
134                     glyphVector.resize(glyphCount);
135                     CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data());
136                     glyphs = glyphVector.data();
137                 }
138                 const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun);
139                 if (!stringIndices) {
140                     indexVector.resize(glyphCount);
141                     CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data());
142                     stringIndices = indexVector.data();
143                 }
144
145                 // When buffer consists of surrogate pairs, CTRunGetStringIndicesPtr and CTRunGetStringIndices
146                 // place the glyphs at indices corresponding to the first character of each pair.
147                 ASSERT(!(bufferLength % length) && (bufferLength / length == 1 || bufferLength / length == 2));
148                 unsigned glyphStep = bufferLength / length;
149                 if (gotBaseFont) {
150                     for (CFIndex i = 0; i < glyphCount; ++i) {
151                         if (stringIndices[i] >= static_cast<CFIndex>(bufferLength)) {
152                             done = true;
153                             break;
154                         }
155                         if (glyphs[i]) {
156                             setGlyphDataForIndex(offset + (stringIndices[i] / glyphStep), glyphs[i], fontData);
157                             haveGlyphs = true;
158                         }
159                     }
160 #if !PLATFORM(IOS)
161                 } else {
162                     const SimpleFontData* runSimple = fontData->getCompositeFontReferenceFontData((NSFont *)runFont);
163                     if (runSimple) {
164                         for (CFIndex i = 0; i < glyphCount; ++i) {
165                             if (stringIndices[i] >= static_cast<CFIndex>(bufferLength)) {
166                                 done = true;
167                                 break;
168                             }
169                             if (glyphs[i]) {
170                                 setGlyphDataForIndex(offset + (stringIndices[i] / glyphStep), glyphs[i], runSimple);
171                                 haveGlyphs = true;
172                             }
173                         }
174                     }
175 #endif // !PLATFORM(IOS)
176                 }
177             }
178         }
179     }
180
181     return haveGlyphs;
182 }
183
184 } // namespace WebCore