2012-02-23 Kenichi Ishibashi <bashi@chromium.org>
+ [Chromium] Add HarfBuzzShaperBase class
+ https://bugs.webkit.org/show_bug.cgi?id=79336
+
+ Extract a part of ComplexTextControllerHarfBuzz class as
+ HarfBuzzShaperBase class. This patch intends to share the code between
+ old HarfBuzz and HarfBuzz-ng.
+
+ Reviewed by Tony Chang.
+
+ No new tests. No behavior change. Existing tests in fast/text should pass.
+
+ * PlatformBlackBerry.cmake: Added HarfBuzzShaperBase.cpp.
+ * WebCore.gyp/WebCore.gyp: Added HarfBuzzShaperBase.(cpp|h).
+ * WebCore.gypi: Ditto.
+ * platform/graphics/harfbuzz/ComplexTextControllerHarfBuzz.cpp:
+ (WebCore::ComplexTextController::ComplexTextController): Removed redundant arguments.
+ (WebCore::ComplexTextController::nextScriptRun): Use m_normalizedBuffer and m_normalizedBufferLength instead of m_run.
+ (WebCore::ComplexTextController::setupFontForScriptRun): Ditto.
+ (WebCore::ComplexTextController::setGlyphPositions): Ditto.
+ * platform/graphics/harfbuzz/ComplexTextControllerHarfBuzz.h:
+ (ComplexTextController):
+ * platform/graphics/harfbuzz/FontHarfBuzz.cpp:
+ (WebCore::Font::drawComplexText): Removed redundant arguments of ComplexTextController constructor.
+ (WebCore::Font::floatWidthForComplexText): Ditto.
+ (WebCore::Font::offsetForPositionForComplexText): Ditto.
+ (WebCore::Font::selectionRectForComplexText): Ditto.
+ * platform/graphics/harfbuzz/HarfBuzzShaperBase.cpp: Added.
+ (WebCore):
+ (WebCore::HarfBuzzShaperBase::HarfBuzzShaperBase):
+ (WebCore::normalizeSpacesAndMirrorChars):
+ (WebCore::HarfBuzzShaperBase::setNormalizedBuffer):
+ (WebCore::HarfBuzzShaperBase::isWordEnd):
+ (WebCore::HarfBuzzShaperBase::determineWordBreakSpacing):
+ (WebCore::HarfBuzzShaperBase::setPadding):
+ * platform/graphics/harfbuzz/HarfBuzzShaperBase.h: Added.
+ (WebCore):
+ (HarfBuzzShaperBase):
+ (WebCore::HarfBuzzShaperBase::~HarfBuzzShaperBase):
+ (WebCore::HarfBuzzShaperBase::isCodepointSpace):
+
+2012-02-23 Kenichi Ishibashi <bashi@chromium.org>
+
Adding WebSocket per-frame DEFLATE extension
https://bugs.webkit.org/show_bug.cgi?id=77522
platform/graphics/harfbuzz/ComplexTextControllerHarfBuzz.cpp
platform/graphics/harfbuzz/FontHarfBuzz.cpp
platform/graphics/harfbuzz/FontPlatformDataHarfBuzz.cpp
+ platform/graphics/harfbuzz/HarfBuzzShaper.cpp
platform/graphics/harfbuzz/HarfBuzzSkia.cpp
platform/graphics/skia/FontCacheSkia.cpp
platform/graphics/skia/GlyphPageTreeNodeSkia.cpp
['include', 'platform/graphics/harfbuzz/FontHarfBuzz\\.cpp$'],
['include', 'platform/graphics/harfbuzz/FontPlatformDataHarfBuzz\\.cpp$'],
['include', 'platform/graphics/harfbuzz/HarfBuzzSkia\\.cpp$'],
+ ['include', 'platform/graphics/harfbuzz/HarfBuzzShaperBase\\.(cpp|h)$'],
['include', 'platform/graphics/skia/SimpleFontDataSkia\\.cpp$'],
],
}, { # use_x11==0
'platform/graphics/harfbuzz/FontPlatformDataHarfBuzz.h',
'platform/graphics/harfbuzz/HarfBuzzSkia.cpp',
'platform/graphics/harfbuzz/HarfBuzzSkia.h',
+ 'platform/graphics/harfbuzz/HarfBuzzShaperBase.cpp',
+ 'platform/graphics/harfbuzz/HarfBuzzShaperBase.h',
'platform/graphics/mac/ColorMac.mm',
'platform/graphics/mac/ComplexTextController.cpp',
'platform/graphics/mac/ComplexTextController.h',
return value >> 6;
}
-ComplexTextController::ComplexTextController(const TextRun& run, int startingX, int startingY, unsigned wordSpacing, unsigned letterSpacing, unsigned padding, const Font* font)
- : m_font(font)
- , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer))
+ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, int startingX, int startingY)
+ : HarfBuzzShaperBase(font, run)
{
- // Do not use |run| inside this constructor. Use |m_run| instead.
+ NormalizeMode mode = m_run.rtl() ? NormalizeMirrorChars : DoNotNormalizeMirrorChars;
+ setNormalizedBuffer(mode);
memset(&m_item, 0, sizeof(m_item));
// We cannot know, ahead of time, how many glyphs a given script run
// will produce. We take a guess that script runs will not produce more
// than twice as many glyphs as there are code points plus a bit of
// padding and fallback if we find that we are wrong.
- createGlyphArrays((m_run.length() + 2) * 2);
+ createGlyphArrays((m_normalizedBufferLength + 2) * 2);
- m_item.log_clusters = new unsigned short[m_run.length()];
+ m_item.log_clusters = new unsigned short[m_normalizedBufferLength];
m_item.face = 0;
m_item.font = allocHarfbuzzFont();
m_item.item.bidiLevel = m_run.rtl();
- m_item.string = m_run.characters();
- m_item.stringLength = m_run.length();
+ m_item.string = m_normalizedBuffer.get();
+ m_item.stringLength = m_normalizedBufferLength;
reset(startingX);
m_startingY = startingY;
- setWordSpacingAdjustment(wordSpacing);
- setLetterSpacingAdjustment(letterSpacing);
- setPadding(padding);
+ setPadding(m_run.expansion());
}
ComplexTextController::~ComplexTextController()
delete[] m_item.log_clusters;
}
-bool ComplexTextController::isWordBreak(unsigned index)
-{
- return index && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index - 1]);
-}
-
-int ComplexTextController::determineWordBreakSpacing(unsigned logClustersIndex)
-{
- int wordBreakSpacing = 0;
- // The first half of the conjunction works around the case where
- // output glyphs aren't associated with any codepoints by the
- // clusters log.
- if (logClustersIndex < m_item.item.length
- && isWordBreak(m_item.item.pos + logClustersIndex)) {
- 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;
-}
-
-// setPadding sets a number of pixels to be distributed across the TextRun.
-// WebKit uses this to justify text.
-void ComplexTextController::setPadding(int padding)
-{
- m_padding = padding;
- m_padError = 0;
- if (!m_padding)
- return;
-
- // If we have padding to distribute, then we try to give an equal
- // amount to each space. The last space gets the smaller amount, if
- // any.
- unsigned numWordBreaks = 0;
-
- for (unsigned i = 0; i < m_item.stringLength; i++) {
- if (isWordBreak(i))
- numWordBreaks++;
- }
-
- if (numWordBreaks)
- m_padPerWordBreak = m_padding / numWordBreaks;
- else
- m_padPerWordBreak = 0;
-}
-
void ComplexTextController::reset(int offset)
{
m_indexOfNextScriptRun = 0;
bool ComplexTextController::nextScriptRun()
{
// Ensure we're not pointing at the small caps buffer.
- m_item.string = m_run.characters();
+ m_item.string = m_normalizedBuffer.get();
- if (!hb_utf16_script_run_next(0, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ if (!hb_utf16_script_run_next(0, &m_item.item, m_normalizedBuffer.get(), m_normalizedBufferLength, &m_indexOfNextScriptRun))
return false;
// It is actually wrong to consider script runs at all in this code.
// case change while in small-caps mode always results in different
// FontData, so we only need to check the first character's case.
if (m_font->isSmallCaps() && u_islower(m_item.string[m_item.item.pos])) {
- m_smallCapsString = String(m_run.data(m_item.item.pos), m_item.item.length);
+ m_smallCapsString = String(m_normalizedBuffer.get() + m_item.item.pos, m_item.item.length);
m_smallCapsString.makeUpper();
m_item.string = m_smallCapsString.characters();
m_item.item.pos = 0;
// logClustersIndex indexes logClusters for the first codepoint of the current glyph.
// Each time we advance a glyph, we skip over all the codepoints that contributed to the current glyph.
- int logClustersIndex = 0;
+ size_t logClustersIndex = 0;
// Iterate through the glyphs in logical order, flipping for RTL where necessary.
// Glyphs are positioned starting from m_offsetX; in RTL mode they go leftwards from there.
for (size_t i = 0; i < m_item.num_glyphs; ++i) {
- while (static_cast<unsigned>(logClustersIndex) < m_item.item.length && m_item.log_clusters[logClustersIndex] < i)
+ while (logClustersIndex < m_item.item.length && m_item.log_clusters[logClustersIndex] < i)
logClustersIndex++;
// If the current glyph is just after a space, add in the word spacing.
- position += determineWordBreakSpacing(logClustersIndex);
+ if (logClustersIndex < m_item.item.length && isWordEnd(m_item.item.pos + logClustersIndex))
+ position += determineWordBreakSpacing();
m_glyphs16[i] = m_item.glyphs[i];
double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
m_offsetX += m_pixelWidth * rtlFlip;
}
-void ComplexTextController::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar* destination, int length)
-{
- int position = 0;
- bool error = false;
- // Iterate characters in source and mirror character if needed.
- 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 (rtl)
- character = u_charMirror(character);
- U16_APPEND(destination, position, length, character, error);
- ASSERT_UNUSED(error, !error);
- position = nextPosition;
- }
-}
-
-const TextRun& ComplexTextController::getNormalizedTextRun(const TextRun& originalRun, OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer)
-{
- // Normalize the text run in three ways:
- // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
- // (U+0300..) are used in the run. This conversion is necessary since most OpenType
- // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
- // their GSUB tables.
- //
- // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
- // the API returns FALSE (= not normalized) for complex runs that don't require NFC
- // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
- // Harfbuzz will do the same thing for us using the GSUB table.
- // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
- // for characters like '\n' otherwise.
- // 3) Convert mirrored characters such as parenthesis for rtl text.
-
- // Convert to NFC form if the text has diacritical marks.
- icu::UnicodeString normalizedString;
- UErrorCode error = U_ZERO_ERROR;
-
- for (int i = 0; i < originalRun.length(); ++i) {
- UChar ch = originalRun[i];
- if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
- icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(),
- originalRun.length()), UNORM_NFC, 0 /* no options */,
- normalizedString, error);
- if (U_FAILURE(error))
- return originalRun;
- break;
- }
- }
-
- // Normalize space and mirror parenthesis for rtl text.
- int normalizedBufferLength;
- const UChar* sourceText;
- if (normalizedString.isEmpty()) {
- normalizedBufferLength = originalRun.length();
- sourceText = originalRun.characters();
- } else {
- normalizedBufferLength = normalizedString.length();
- sourceText = normalizedString.getBuffer();
- }
-
- normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]);
-
- normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(), normalizedBufferLength);
-
- normalizedRun = adoptPtr(new TextRun(originalRun));
- normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength);
- return *normalizedRun;
-}
-
int ComplexTextController::glyphIndexForXPositionInScriptRun(int targetX) const
{
// Iterate through the glyphs in logical order, seeing whether targetX falls between the previous
#ifndef ComplexTextControllerHarfBuzz_h
#define ComplexTextControllerHarfBuzz_h
+#include "HarfBuzzShaperBase.h"
#include "HarfBuzzSkia.h"
#include "SkPoint.h"
#include "SkScalar.h"
// Once you have setup the object, call |nextScriptRun| to get the first script
// run. This will return false when the iteration is complete. At any time you
// can call |reset| to start over again.
-class ComplexTextController {
+class ComplexTextController : public HarfBuzzShaperBase {
public:
- ComplexTextController(const TextRun&, int startingX, int startingY, unsigned wordSpacing, unsigned letterSpacing, unsigned padding, const Font*);
- ~ComplexTextController();
-
- bool isWordBreak(unsigned);
- int determineWordBreakSpacing(unsigned);
- // setPadding sets a number of pixels to be distributed across the TextRun.
- // WebKit uses this to justify text.
- void setPadding(int);
+ ComplexTextController(const Font*, const TextRun&, int startingX, int startingY);
+ virtual ~ComplexTextController();
+
void reset(int offset);
// Advance to the next script run, returning false when the end of the
// TextRun has been reached.
bool nextScriptRun();
float widthOfFullRun();
- // setWordSpacingAdjustment sets a delta (in pixels) which is applied at
- // each word break in the TextRun.
- void setWordSpacingAdjustment(int wordSpacingAdjustment) { m_wordSpacingAdjustment = wordSpacingAdjustment; }
-
- // setLetterSpacingAdjustment sets an additional number of pixels that is
- // added to the advance after each output cluster. This matches the behaviour
- // of WidthIterator::advance.
- void setLetterSpacingAdjustment(int letterSpacingAdjustment) { m_letterSpacing = letterSpacingAdjustment; }
- int letterSpacing() const { return m_letterSpacing; }
-
void setupForRTL();
bool rtl() const { return m_run.rtl(); }
const uint16_t* glyphs() const { return m_glyphs16; }
void shapeGlyphs();
void setGlyphPositions(bool);
- static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl, UChar* destination, int length);
- static const TextRun& getNormalizedTextRun(const TextRun& originalRun, OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer);
-
- // This matches the logic in RenderBlock::findNextLineBreak
- static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
-
int glyphIndexForXPositionInScriptRun(int targetX) const;
- const Font* const m_font;
const SimpleFontData* m_currentFontData;
HB_ShaperItem m_item;
uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
unsigned m_pixelWidth; // Width (in px) of the current script run.
unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
- OwnPtr<TextRun> m_normalizedRun;
- OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
- const TextRun& m_run;
- int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
- float m_padding; // pixels to be distributed over the line at word breaks.
- float m_padPerWordBreak; // pixels to be added to each word break.
- float m_padError; // |m_padPerWordBreak| might have a fractional component.
- // Since we only add a whole number of padding pixels at
- // each word break we accumulate error. This is the
- // number of pixels that we are behind so far.
- int m_letterSpacing; // pixels to be added after each glyph.
String m_smallCapsString; // substring of m_run converted to small caps.
};
setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
}
- ComplexTextController controller(run, point.x(), point.y(), wordSpacing(), letterSpacing(), run.expansion(), this);
-
+ ComplexTextController controller(this, run, point.x(), point.y());
if (run.rtl())
controller.setupForRTL();
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const
{
- ComplexTextController controller(run, 0, 0, wordSpacing(), letterSpacing(), run.expansion(), this);
+ ComplexTextController controller(this, run, 0, 0);
return controller.widthOfFullRun();
}
// (Mac code ignores includePartialGlyphs, and they don't know what it's
// supposed to do, so we just ignore it as well.)
- ComplexTextController controller(run, 0, 0, wordSpacing(), letterSpacing(), run.expansion(), this);
+ ComplexTextController controller(this, run, 0, 0);
if (run.rtl())
controller.setupForRTL();
return controller.offsetForPosition(targetX);
const FloatPoint& point, int height,
int from, int to) const
{
- ComplexTextController controller(run, 0, 0, wordSpacing(), letterSpacing(), run.expansion(), this);
+ ComplexTextController controller(this, run, 0, 0);
if (run.rtl())
controller.setupForRTL();
return controller.selectionRect(point, height, from, to);
--- /dev/null
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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_run(run)
+ , m_wordSpacingAdjustment(font->wordSpacing())
+ , m_letterSpacing(font->letterSpacing())
+{
+}
+
+static void normalizeSpacesAndMirrorChars(const UChar* source, UChar* destination, int length, HarfBuzzShaperBase::NormalizeMode normalizeMode)
+{
+ int position = 0;
+ bool error = false;
+ // Iterate characters in source and mirror character if needed.
+ 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(!error);
+ position = nextPosition;
+ }
+}
+
+void HarfBuzzShaperBase::setNormalizedBuffer(NormalizeMode normalizeMode)
+{
+ // Normalize the text run in three ways:
+ // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
+ // (U+0300..) are used in the run. This conversion is necessary since most OpenType
+ // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
+ // their GSUB tables.
+ //
+ // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
+ // the API returns FALSE (= not normalized) for complex runs that don't require NFC
+ // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
+ // HarfBuzz will do the same thing for us using the GSUB table.
+ // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
+ // for characters like '\n' otherwise.
+ // 3) Convert mirrored characters such as parenthesis for rtl text.
+
+ // Convert to NFC form if the text has diacritical marks.
+ 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 /* no options */,
+ 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)
+{
+ // This could refer a high-surrogate, but should work.
+ 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;
+}
+
+// setPadding sets a number of pixels to be distributed across the TextRun.
+// WebKit uses this to justify text.
+void HarfBuzzShaperBase::setPadding(int padding)
+{
+ m_padding = padding;
+ m_padError = 0;
+ if (!m_padding)
+ return;
+
+ // If we have padding to distribute, then we try to give an equal
+ // amount to each space. The last space gets the smaller amount, if
+ // any.
+ 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;
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HarfBuzzShaperBase_h
+#define HarfBuzzShaperBase_h
+
+#include "TextRun.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace WebCore {
+
+class Font;
+
+class HarfBuzzShaperBase {
+public:
+ enum NormalizeMode {
+ DoNotNormalizeMirrorChars,
+ NormalizeMirrorChars
+ };
+
+ HarfBuzzShaperBase(const Font*, const TextRun&);
+ virtual ~HarfBuzzShaperBase() { }
+
+protected:
+ void setNormalizedBuffer(NormalizeMode = DoNotNormalizeMirrorChars);
+
+ bool isWordEnd(unsigned);
+ int determineWordBreakSpacing();
+ // setPadding sets a number of pixels to be distributed across the TextRun.
+ // WebKit uses this to justify text.
+ void setPadding(int);
+
+ // This matches the logic in RenderBlock::findNextLineBreak
+ static bool isCodepointSpace(UChar c) { return c == ' ' || c == '\t'; }
+
+ const Font* m_font;
+ OwnArrayPtr<UChar> m_normalizedBuffer;
+ unsigned m_normalizedBufferLength;
+ const TextRun& m_run;
+
+ int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
+ float m_padding; // pixels to be distributed over the line at word breaks.
+ float m_padPerWordBreak; // pixels to be added to each word break.
+ float m_padError; // |m_padPerWordBreak| might have a fractional component.
+ // Since we only add a whole number of padding pixels at
+ // each word break we accumulate error. This is the
+ // number of pixels that we are behind so far.
+ int m_letterSpacing; // pixels to be added after each glyph.
+};
+
+} // namespace WebCore
+
+#endif // HarfBuzzShaperBase_h