18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met: 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer. 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * documentation and/or other materials provided with the distribution. 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * its contributors may be used to endorse or promote products derived 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * from this software without specific prior written permission. 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h" 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GlyphPageTreeNode.h" 31f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "Font.h" 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SimpleFontData.h" 348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "WebCoreSystemInterface.h" 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <ApplicationServices/ApplicationServices.h> 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore { 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 39f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#ifndef BUILDING_ON_TIGER 40f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochstatic bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) 41f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch{ 422bde8e466a4451c7319e3a072d118917957d6554Steve Block if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) { 432fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Ideographs don't have a vertical variant or width variants. 44f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch for (unsigned i = 0; i < bufferLength; ++i) { 45f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (!Font::isCJKIdeograph(buffer[i])) 46f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return true; 47f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 48f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 49f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 50f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch return false; 51f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch} 52f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#endif 53f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) 558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project bool haveGlyphs = false; 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#ifndef BUILDING_ON_TIGER 59f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (!shouldUseCoreText(buffer, bufferLength, fontData)) { 60e14391e94c850b8bd03680c23b38978db68687a8John Reck Vector<CGGlyph, 512> glyphs(bufferLength); 61e14391e94c850b8bd03680c23b38978db68687a8John Reck wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength); 62e14391e94c850b8bd03680c23b38978db68687a8John Reck for (unsigned i = 0; i < length; ++i) { 63e14391e94c850b8bd03680c23b38978db68687a8John Reck if (!glyphs[i]) 64e14391e94c850b8bd03680c23b38978db68687a8John Reck setGlyphDataForIndex(offset + i, 0, 0); 65e14391e94c850b8bd03680c23b38978db68687a8John Reck else { 66e14391e94c850b8bd03680c23b38978db68687a8John Reck setGlyphDataForIndex(offset + i, glyphs[i], fontData); 67e14391e94c850b8bd03680c23b38978db68687a8John Reck haveGlyphs = true; 68e14391e94c850b8bd03680c23b38978db68687a8John Reck } 69e14391e94c850b8bd03680c23b38978db68687a8John Reck } 70e14391e94c850b8bd03680c23b38978db68687a8John Reck } else { 71e14391e94c850b8bd03680c23b38978db68687a8John Reck // We ask CoreText for possible vertical variant glyphs 72e14391e94c850b8bd03680c23b38978db68687a8John Reck RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); 732bde8e466a4451c7319e3a072d118917957d6554Steve Block RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal))); 74e14391e94c850b8bd03680c23b38978db68687a8John Reck RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); 75e14391e94c850b8bd03680c23b38978db68687a8John Reck 76e14391e94c850b8bd03680c23b38978db68687a8John Reck CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); 77e14391e94c850b8bd03680c23b38978db68687a8John Reck CFIndex runCount = CFArrayGetCount(runArray); 78e14391e94c850b8bd03680c23b38978db68687a8John Reck 79e14391e94c850b8bd03680c23b38978db68687a8John Reck // Initialize glyph entries 80e14391e94c850b8bd03680c23b38978db68687a8John Reck for (unsigned index = 0; index < length; ++index) 81e14391e94c850b8bd03680c23b38978db68687a8John Reck setGlyphDataForIndex(offset + index, 0, 0); 82e14391e94c850b8bd03680c23b38978db68687a8John Reck 83e14391e94c850b8bd03680c23b38978db68687a8John Reck Vector<CGGlyph, 512> glyphVector; 84e14391e94c850b8bd03680c23b38978db68687a8John Reck Vector<CFIndex, 512> indexVector; 85e14391e94c850b8bd03680c23b38978db68687a8John Reck bool done = false; 8681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 8781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may 8881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // be non-CFEqual to fontData->platformData().cgFont(). 8981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0)); 9081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 91e14391e94c850b8bd03680c23b38978db68687a8John Reck for (CFIndex r = 0; r < runCount && !done ; ++r) { 92e14391e94c850b8bd03680c23b38978db68687a8John Reck // CTLine could map characters over multiple fonts using its own font fallback list. 93e14391e94c850b8bd03680c23b38978db68687a8John Reck // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont(). 94e14391e94c850b8bd03680c23b38978db68687a8John Reck CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); 95e14391e94c850b8bd03680c23b38978db68687a8John Reck ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); 96e14391e94c850b8bd03680c23b38978db68687a8John Reck 97e14391e94c850b8bd03680c23b38978db68687a8John Reck CFDictionaryRef attributes = CTRunGetAttributes(ctRun); 98e14391e94c850b8bd03680c23b38978db68687a8John Reck CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName)); 99e14391e94c850b8bd03680c23b38978db68687a8John Reck RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0)); 100e14391e94c850b8bd03680c23b38978db68687a8John Reck // Use CGFont here as CFEqual for CTFont counts all attributes for font. 10181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (CFEqual(cgFont.get(), runCGFont.get())) { 102e14391e94c850b8bd03680c23b38978db68687a8John Reck // This run uses the font we want. Extract glyphs. 103e14391e94c850b8bd03680c23b38978db68687a8John Reck CFIndex glyphCount = CTRunGetGlyphCount(ctRun); 104e14391e94c850b8bd03680c23b38978db68687a8John Reck const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun); 105e14391e94c850b8bd03680c23b38978db68687a8John Reck if (!glyphs) { 106e14391e94c850b8bd03680c23b38978db68687a8John Reck glyphVector.resize(glyphCount); 107e14391e94c850b8bd03680c23b38978db68687a8John Reck CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data()); 108e14391e94c850b8bd03680c23b38978db68687a8John Reck glyphs = glyphVector.data(); 109e14391e94c850b8bd03680c23b38978db68687a8John Reck } 110e14391e94c850b8bd03680c23b38978db68687a8John Reck const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun); 111e14391e94c850b8bd03680c23b38978db68687a8John Reck if (!stringIndices) { 112e14391e94c850b8bd03680c23b38978db68687a8John Reck indexVector.resize(glyphCount); 113e14391e94c850b8bd03680c23b38978db68687a8John Reck CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data()); 114e14391e94c850b8bd03680c23b38978db68687a8John Reck stringIndices = indexVector.data(); 115e14391e94c850b8bd03680c23b38978db68687a8John Reck } 116e14391e94c850b8bd03680c23b38978db68687a8John Reck 117e14391e94c850b8bd03680c23b38978db68687a8John Reck for (CFIndex i = 0; i < glyphCount; ++i) { 118e14391e94c850b8bd03680c23b38978db68687a8John Reck if (stringIndices[i] >= static_cast<CFIndex>(length)) { 119e14391e94c850b8bd03680c23b38978db68687a8John Reck done = true; 120e14391e94c850b8bd03680c23b38978db68687a8John Reck break; 121e14391e94c850b8bd03680c23b38978db68687a8John Reck } 122e14391e94c850b8bd03680c23b38978db68687a8John Reck if (glyphs[i]) { 123e14391e94c850b8bd03680c23b38978db68687a8John Reck setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData); 124e14391e94c850b8bd03680c23b38978db68687a8John Reck haveGlyphs = true; 125e14391e94c850b8bd03680c23b38978db68687a8John Reck } 126e14391e94c850b8bd03680c23b38978db68687a8John Reck } 127e14391e94c850b8bd03680c23b38978db68687a8John Reck } 1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#else 1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Use an array of long so we get good enough alignment. 1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)]; 1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector); 1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (status != noErr) 1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // This should never happen, perhaps indicates a bad font! If it does the 1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // font substitution code will find an alternate font. 1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector); 1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector); 1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (numGlyphs != length) { 1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // This should never happen, perhaps indicates a bad font? 1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // If it does happen, the font substitution code will find an alternate font. 1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project wkClearGlyphVector(&glyphVector); 1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector); 1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (unsigned i = 0; i < length; i++) { 1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Glyph glyph = glyphRecord->glyphID; 1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!glyph) 1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project setGlyphDataForIndex(offset + i, 0, 0); 1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project else { 1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project setGlyphDataForIndex(offset + i, glyph, fontData); 1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project haveGlyphs = true; 1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector)); 1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project wkClearGlyphVector(&glyphVector); 1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif 1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return haveGlyphs; 1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore 168