ComplexTextControllerCoreText.cpp [plain text]
#include "config.h"
#if USE(CORE_TEXT)
#include "ComplexTextController.h"
#include "Font.h"
#include "TextRun.h"
#include "WebCoreSystemInterface.h"
#if PLATFORM(WX)
#include <ApplicationServices/ApplicationServices.h>
#else
#include <CoreText/CoreText.h>
#endif
#if defined(BUILDING_ON_LEOPARD)
extern "C" {
void CTRunGetAdvances(CTRunRef run, CFRange range, CGSize buffer[]);
const CGSize* CTRunGetAdvancesPtr(CTRunRef run);
extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
}
#endif
namespace WebCore {
ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, CFRange runRange)
: m_fontData(fontData)
, m_characters(characters)
, m_stringLocation(stringLocation)
, m_stringLength(stringLength)
, m_indexEnd(runRange.location + runRange.length)
, m_isMonotonic(true)
{
m_glyphCount = CTRunGetGlyphCount(ctRun);
m_coreTextIndices = CTRunGetStringIndicesPtr(ctRun);
if (!m_coreTextIndices) {
m_coreTextIndicesVector.grow(m_glyphCount);
CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), m_coreTextIndicesVector.data());
m_coreTextIndices = m_coreTextIndicesVector.data();
}
m_glyphs = CTRunGetGlyphsPtr(ctRun);
if (!m_glyphs) {
m_glyphsVector.grow(m_glyphCount);
CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), m_glyphsVector.data());
m_glyphs = m_glyphsVector.data();
}
m_advances = CTRunGetAdvancesPtr(ctRun);
if (!m_advances) {
m_advancesVector.grow(m_glyphCount);
CTRunGetAdvances(ctRun, CFRangeMake(0, 0), m_advancesVector.data());
m_advances = m_advancesVector.data();
}
}
void ComplexTextController::ComplexTextRun::createTextRunFromFontDataCoreText(bool ltr)
{
m_coreTextIndicesVector.reserveInitialCapacity(m_stringLength);
unsigned r = 0;
while (r < m_stringLength) {
m_coreTextIndicesVector.uncheckedAppend(r);
if (U_IS_SURROGATE(m_characters[r])) {
ASSERT(r + 1 < m_stringLength);
ASSERT(U_IS_SURROGATE_LEAD(m_characters[r]));
ASSERT(U_IS_TRAIL(m_characters[r + 1]));
r += 2;
} else
r++;
}
m_glyphCount = m_coreTextIndicesVector.size();
if (!ltr) {
for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
std::swap(m_coreTextIndicesVector[r], m_coreTextIndicesVector[end]);
}
m_coreTextIndices = m_coreTextIndicesVector.data();
m_glyphsVector.fill(0, m_glyphCount);
m_glyphs = m_glyphsVector.data();
m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount);
m_advances = m_advancesVector.data();
}
struct ProviderInfo {
const UChar* cp;
unsigned length;
CFDictionaryRef attributes;
};
static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* charCount, CFDictionaryRef* attributes, void* refCon)
{
ProviderInfo* info = static_cast<struct ProviderInfo*>(refCon);
if (stringIndex < 0 || static_cast<unsigned>(stringIndex) >= info->length)
return 0;
*charCount = info->length - stringIndex;
*attributes = info->attributes;
return info->cp + stringIndex;
}
void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
{
if (!fontData) {
m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
return;
}
if (m_fallbackFonts && fontData != m_font.primaryFont())
m_fallbackFonts->add(fontData);
RetainPtr<CTLineRef> line;
if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
const short ltrForcedEmbeddingLevelValue = 0;
const short rtlForcedEmbeddingLevelValue = 1;
static const void* ltrOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, <rForcedEmbeddingLevelValue) };
static const void* rtlOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &rtlForcedEmbeddingLevelValue) };
static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, WTF_ARRAY_LENGTH(optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, WTF_ARRAY_LENGTH(optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) };
RetainPtr<CTTypesetterRef> typesetter(AdoptCF, wkCreateCTTypesetterWithUniCharProviderAndOptions(&provideStringAndAttributes, 0, &info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
#else
RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull));
RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation())));
RetainPtr<CTTypesetterRef> typesetter(AdoptCF, CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
#endif
line.adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
} else {
ProviderInfo info = { cp, length, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()) };
line.adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
}
m_coreTextLines.append(line.get());
CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
CFIndex runCount = CFArrayGetCount(runArray);
for (CFIndex r = 0; r < runCount; r++) {
CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
CFRange runRange = CTRunGetStringRange(ctRun);
m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length, runRange));
}
}
}
#endif // USE(CORE_TEXT)