blob: a33caf38e0748e8287e26a18a3bc5a689f9a1126 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "CaseMappingHarfBuzzBufferFiller.h"
#include "wtf/text/WTFString.h"
namespace blink {
static const uint16_t* toUint16(const UChar* src)
{
// FIXME: This relies on undefined behavior however it works on the
// current versions of all compilers we care about and avoids making
// a copy of the string.
static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same size as uint16_t");
return reinterpret_cast<const uint16_t*>(src);
}
CaseMappingHarfBuzzBufferFiller::CaseMappingHarfBuzzBufferFiller(
CaseMapIntend caseMapIntend,
AtomicString locale,
hb_buffer_t* harfBuzzBuffer,
const UChar* buffer,
unsigned bufferLength,
unsigned startIndex,
unsigned numCharacters)
: m_harfBuzzBuffer(harfBuzzBuffer)
{
if (caseMapIntend == CaseMapIntend::KeepSameCase) {
hb_buffer_add_utf16(m_harfBuzzBuffer,
toUint16(buffer),
bufferLength,
startIndex,
numCharacters);
} else {
String caseMappedText;
if (caseMapIntend == CaseMapIntend::UpperCase) {
caseMappedText = String(buffer, bufferLength).upper(locale);
} else {
caseMappedText = String(buffer, bufferLength).lower(locale);
}
if (caseMappedText.length() != bufferLength) {
fillSlowCase(caseMapIntend, locale, buffer, bufferLength, startIndex, numCharacters);
return;
}
ASSERT(caseMappedText.length() == bufferLength);
ASSERT(!caseMappedText.is8Bit());
hb_buffer_add_utf16(m_harfBuzzBuffer, toUint16(caseMappedText.characters16()),
bufferLength, startIndex, numCharacters);
}
}
// TODO(drott): crbug.com/623940 Fix lack of context sensitive case mapping here.
void CaseMappingHarfBuzzBufferFiller::fillSlowCase(
CaseMapIntend caseMapIntend,
AtomicString locale,
const UChar* buffer,
unsigned bufferLength,
unsigned startIndex,
unsigned numCharacters)
{
// Record pre-context.
hb_buffer_add_utf16(m_harfBuzzBuffer, toUint16(buffer), bufferLength, startIndex, 0);
for (unsigned charIndex = startIndex; charIndex < startIndex + numCharacters;) {
unsigned newCharIndex = charIndex;
U16_FWD_1(buffer, newCharIndex, numCharacters);
String charByChar(&buffer[charIndex], newCharIndex - charIndex);
String caseMappedChar;
if (caseMapIntend == CaseMapIntend::UpperCase)
caseMappedChar = charByChar.upper(locale);
else
caseMappedChar = charByChar.lower(locale);
for (unsigned j = 0; j < caseMappedChar.length();) {
UChar32 codepoint = 0;
U16_NEXT(caseMappedChar.characters16(), j, caseMappedChar.length(), codepoint);
// Add all characters of the case mapping result at the same cluster position.
hb_buffer_add(m_harfBuzzBuffer, codepoint, charIndex);
}
charIndex = newCharIndex;
}
// Record post-context
hb_buffer_add_utf16(m_harfBuzzBuffer, toUint16(buffer), bufferLength, startIndex + numCharacters, 0);
}
} // namespace blink