HarfBuzzShaperBase.cpp [plain text]
#include "config.h"
#include "HarfBuzzShaperBase.h"
#include "Font.h"
#include <unicode/normlzr.h>
#include <unicode/uchar.h>
#include <wtf/MathExtras.h>
#include <wtf/unicode/Unicode.h>
namespace WebCore {
HarfBuzzShaperBase::HarfBuzzShaperBase(const Font* font, const TextRun& run)
: m_font(font)
, m_normalizedBufferLength(0)
, m_run(run)
, m_wordSpacingAdjustment(font->wordSpacing())
, m_padding(0)
, m_padPerWordBreak(0)
, m_padError(0)
, m_letterSpacing(font->letterSpacing())
{
}
static void normalizeSpacesAndMirrorChars(const UChar* source, UChar* destination, int length, HarfBuzzShaperBase::NormalizeMode normalizeMode)
{
int position = 0;
bool error = false;
while (position < length) {
UChar32 character;
int nextPosition = position;
U16_NEXT(source, nextPosition, length, character);
if (Font::treatAsSpace(character))
character = ' ';
else if (Font::treatAsZeroWidthSpace(character))
character = zeroWidthSpace;
else if (normalizeMode == HarfBuzzShaperBase::NormalizeMirrorChars)
character = u_charMirror(character);
U16_APPEND(destination, position, length, character, error);
ASSERT_UNUSED(error, !error);
position = nextPosition;
}
}
void HarfBuzzShaperBase::setNormalizedBuffer(NormalizeMode normalizeMode)
{
icu::UnicodeString normalizedString;
UErrorCode error = U_ZERO_ERROR;
for (int i = 0; i < m_run.length(); ++i) {
UChar ch = m_run[i];
if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
icu::Normalizer::normalize(icu::UnicodeString(m_run.characters(),
m_run.length()), UNORM_NFC, 0 ,
normalizedString, error);
if (U_FAILURE(error))
normalizedString.remove();
break;
}
}
const UChar* sourceText;
if (normalizedString.isEmpty()) {
m_normalizedBufferLength = m_run.length();
sourceText = m_run.characters();
} else {
m_normalizedBufferLength = normalizedString.length();
sourceText = normalizedString.getBuffer();
}
m_normalizedBuffer = adoptArrayPtr(new UChar[m_normalizedBufferLength + 1]);
normalizeSpacesAndMirrorChars(sourceText, m_normalizedBuffer.get(), m_normalizedBufferLength, normalizeMode);
}
bool HarfBuzzShaperBase::isWordEnd(unsigned index)
{
return index && isCodepointSpace(m_normalizedBuffer[index]) && !isCodepointSpace(m_normalizedBuffer[index - 1]);
}
int HarfBuzzShaperBase::determineWordBreakSpacing()
{
int wordBreakSpacing = m_wordSpacingAdjustment;
if (m_padding > 0) {
int toPad = roundf(m_padPerWordBreak + m_padError);
m_padError += m_padPerWordBreak - toPad;
if (m_padding < toPad)
toPad = m_padding;
m_padding -= toPad;
wordBreakSpacing += toPad;
}
return wordBreakSpacing;
}
void HarfBuzzShaperBase::setPadding(int padding)
{
m_padding = padding;
m_padError = 0;
if (!m_padding)
return;
unsigned numWordEnds = 0;
for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
if (isWordEnd(i))
numWordEnds++;
}
if (numWordEnds)
m_padPerWordBreak = m_padding / numWordEnds;
else
m_padPerWordBreak = 0;
}
}