Commit 9cd3ea41 authored by mitz@apple.com's avatar mitz@apple.com

WebCore: Part of <rdar://problem/6649734> Text repainting does not account for...

WebCore: Part of <rdar://problem/6649734> Text repainting does not account for glyphs which draw outside the typographic bounds of the font
https://bugs.webkit.org/show_bug.cgi?id=6274

Reviewed by Adele Peterson.

Account for glyph overflow of characters in the range U+1E00..U+2000, but without sending them
through the complex text code path. Instead, introduce a variant of the fast path that tracks
glyph overflow.

* platform/graphics/Font.cpp:
(WebCore::Font::drawText): Use codePath().
(WebCore::Font::floatWidth): Use codePath(). Pass the GlyphOverflow pointer through to
floatWidthForSimpleText() if the code path is SimpleWithGlyphOverflow.
(WebCore::Font::selectionRectForText): Use codePath().
(WebCore::Font::offsetForPosition): Ditto.
* platform/graphics/Font.h: Replaced canUseGlyphCache() with codePath(). Added a GlyphOverflow
parameter to floatWidthForSimpleText().
* platform/graphics/FontFastPath.cpp:
Removed ROMAN_AND_GREEK_DIACRITICS_CAN_USE_GLYPH_CACHE.
(WebCore::Font::codePath): Renamed canUseGlyphCache() to this. Where it used to return false,
it now returns Complex. Where it used to return true, it now returns Simple, except for
the range U+1E00..U+2000, where it now returns SimpleWithGlyphOverflow.
(WebCore::Font::floatWidthForSimpleText): Added a GlyphOverflow parameter. If not 0, have the
width iterator account for glyph bounds, then update the GlyphOverflow accordingly.
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::WidthIterator): Added boolean parameter telling the width iterator
whether to account for glyph bounds. Initialize m_accountForGlyphBounds accordingly. Initialize
m_maxGlyphBoundingBoxY, m_minGlyphBoundingBoxY, m_firstGlyphOverflow and m_lastGlyphOverflow.
(WebCore::WidthIterator::advance): If accounting for glyph bounds, update the above member variables.
* platform/graphics/WidthIterator.h:
(WebCore::WidthIterator::maxGlyphBoundingBoxY): Added this accessor.
(WebCore::WidthIterator::minGlyphBoundingBoxY): Ditto.
(WebCore::WidthIterator::firstGlyphOverflow): Ditto.
(WebCore::WidthIterator::lastGlyphOverflow): Ditto.

LayoutTests: Updated results for <rdar://problem/6649734> Text repainting does not account for glyphs which draw outside the typographic bounds of the font
https://bugs.webkit.org/show_bug.cgi?id=6274

Reviewed by Adele Peterson.

* platform/mac/fast/repaint/stacked-diacritics-expected.checksum:
* platform/mac/fast/repaint/stacked-diacritics-expected.png:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@58585 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 42ded7b6
2010-04-30 Dan Bernstein <mitz@apple.com>
Reviewed by Adele Peterson.
Updated results for <rdar://problem/6649734> Text repainting does not account for glyphs which draw outside the typographic bounds of the font
https://bugs.webkit.org/show_bug.cgi?id=6274
* platform/mac/fast/repaint/stacked-diacritics-expected.checksum:
* platform/mac/fast/repaint/stacked-diacritics-expected.png:
2010-04-30 Chris Marrin <cmarrin@apple.com>
Reviewed by Simon Fraser.
......
214a62226351798b782ad9c839ab900d
\ No newline at end of file
61cab097914525fb7f7a07989330012e
\ No newline at end of file
2010-04-30 Dan Bernstein <mitz@apple.com>
Reviewed by Adele Peterson.
Part of <rdar://problem/6649734> Text repainting does not account for glyphs which draw outside the typographic bounds of the font
https://bugs.webkit.org/show_bug.cgi?id=6274
Account for glyph overflow of characters in the range U+1E00..U+2000, but without sending them
through the complex text code path. Instead, introduce a variant of the fast path that tracks
glyph overflow.
* platform/graphics/Font.cpp:
(WebCore::Font::drawText): Use codePath().
(WebCore::Font::floatWidth): Use codePath(). Pass the GlyphOverflow pointer through to
floatWidthForSimpleText() if the code path is SimpleWithGlyphOverflow.
(WebCore::Font::selectionRectForText): Use codePath().
(WebCore::Font::offsetForPosition): Ditto.
* platform/graphics/Font.h: Replaced canUseGlyphCache() with codePath(). Added a GlyphOverflow
parameter to floatWidthForSimpleText().
* platform/graphics/FontFastPath.cpp:
Removed ROMAN_AND_GREEK_DIACRITICS_CAN_USE_GLYPH_CACHE.
(WebCore::Font::codePath): Renamed canUseGlyphCache() to this. Where it used to return false,
it now returns Complex. Where it used to return true, it now returns Simple, except for
the range U+1E00..U+2000, where it now returns SimpleWithGlyphOverflow.
(WebCore::Font::floatWidthForSimpleText): Added a GlyphOverflow parameter. If not 0, have the
width iterator account for glyph bounds, then update the GlyphOverflow accordingly.
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::WidthIterator): Added boolean parameter telling the width iterator
whether to account for glyph bounds. Initialize m_accountForGlyphBounds accordingly. Initialize
m_maxGlyphBoundingBoxY, m_minGlyphBoundingBoxY, m_firstGlyphOverflow and m_lastGlyphOverflow.
(WebCore::WidthIterator::advance): If accounting for glyph bounds, update the above member variables.
* platform/graphics/WidthIterator.h:
(WebCore::WidthIterator::maxGlyphBoundingBoxY): Added this accessor.
(WebCore::WidthIterator::minGlyphBoundingBoxY): Ditto.
(WebCore::WidthIterator::firstGlyphOverflow): Ditto.
(WebCore::WidthIterator::lastGlyphOverflow): Ditto.
2010-04-30 Chris Marrin <cmarrin@apple.com>
Reviewed by Simon Fraser.
......@@ -175,7 +175,7 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi
#endif
#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
if (codePath(run) != Complex)
return drawSimpleText(context, run, point, from, to);
#endif
......@@ -190,11 +190,12 @@ float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallb
#endif
#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run)) {
CodePath codePathToUse = codePath(run);
if (codePathToUse != Complex) {
// If the complex text implementation cannot return fallback fonts, avoid
// returning them for simple text as well.
static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0);
return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow ? glyphOverflow : 0);
}
#endif
......@@ -214,7 +215,7 @@ float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsCo
glyphName = "";
#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
if (codePath(run) != Complex)
return floatWidthForSimpleText(run, 0);
#endif
......@@ -231,7 +232,7 @@ FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point,
to = (to == -1 ? run.length() : to);
#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
if (codePath(run) != Complex)
return selectionRectForSimpleText(run, point, h, from, to);
#endif
......@@ -246,7 +247,7 @@ int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs
#endif
#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
if (codePath(run) != Complex)
return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
#endif
......
......@@ -150,6 +150,10 @@ public:
static void setShouldUseSmoothing(bool);
static bool shouldUseSmoothing();
#if USE(FONT_FAST_PATH)
enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow };
#endif
private:
#if ENABLE(SVG_FONTS)
void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
......@@ -160,11 +164,11 @@ private:
#endif
#if USE(FONT_FAST_PATH)
bool canUseGlyphCache(const TextRun&) const;
CodePath codePath(const TextRun&) const;
void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const;
void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const;
float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0) const;
float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const;
FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const;
......@@ -181,7 +185,6 @@ private:
public:
// Useful for debugging the different font rendering code paths.
#if USE(FONT_FAST_PATH)
enum CodePath { Auto, Simple, Complex };
static void setCodePath(CodePath);
static CodePath codePath();
static CodePath s_codePath;
......
......@@ -36,10 +36,6 @@
#include <wtf/MathExtras.h>
#include <wtf/unicode/Unicode.h>
#ifndef ROMAN_AND_GREEK_DIACRITICS_CAN_USE_GLYPH_CACHE
#define ROMAN_AND_GREEK_DIACRITICS_CAN_USE_GLYPH_CACHE 1
#endif
using namespace WTF;
using namespace Unicode;
......@@ -194,74 +190,64 @@ Font::CodePath Font::codePath()
return s_codePath;
}
bool Font::canUseGlyphCache(const TextRun& run) const
Font::CodePath Font::codePath(const TextRun& run) const
{
switch (s_codePath) {
case Auto:
break;
case Simple:
return true;
case Complex:
return false;
}
if (s_codePath != Auto)
return s_codePath;
// Start from 0 since drawing and highlighting also measure the characters before run->from
for (int i = 0; i < run.length(); i++) {
const UChar c = run[i];
if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
continue;
if (c <= 0x36F)
return false;
return Complex;
if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
continue;
if (c <= 0x05CF)
return false;
return Complex;
if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
continue;
if (c <= 0x1059)
return false;
return Complex;
if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
continue;
if (c <= 0x11FF)
return false;
return Complex;
if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
continue;
if (c <= 0x18AF)
return false;
return Complex;
if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
continue;
if (c <= 0x194F)
return false;
return Complex;
#if !ROMAN_AND_GREEK_DIACRITICS_CAN_USE_GLYPH_CACHE
// FIXME: we should not use complex text path for these characters.
if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
continue;
if (c <= 0x2000)
return false;
#endif
return SimpleWithGlyphOverflow;
if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
continue;
if (c <= 0x20FF)
return false;
return Complex;
if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
continue;
if (c <= 0xFE2F)
return false;
return Complex;
}
if (typesettingFeatures())
return false;
return true;
return Complex;
return Simple;
}
void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
......@@ -326,10 +312,18 @@ void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf
drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
}
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
WidthIterator it(this, run, fallbackFonts);
WidthIterator it(this, run, fallbackFonts, glyphOverflow);
it.advance(run.length(), glyphBuffer);
if (glyphOverflow) {
glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - ascent());
glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - descent());
glyphOverflow->left = ceilf(it.firstGlyphOverflow());
glyphOverflow->right = ceilf(it.lastGlyphOverflow());
}
return it.m_runWidthSoFar;
}
......
......@@ -33,13 +33,14 @@
using namespace WTF;
using namespace Unicode;
using namespace std;
namespace WebCore {
// According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts)
WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds)
: m_font(font)
, m_run(run)
, m_end(run.length())
......@@ -47,6 +48,11 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const
, m_runWidthSoFar(0)
, m_finalRoundingWidth(0)
, m_fallbackFonts(fallbackFonts)
, m_accountForGlyphBounds(accountForGlyphBounds)
, m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
, m_minGlyphBoundingBoxY(numeric_limits<float>::max())
, m_firstGlyphOverflow(0)
, m_lastGlyphOverflow(0)
{
// If the padding is non-zero, count the number of spaces in the run
// and divide that by the padding for per space addition.
......@@ -79,6 +85,7 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
float runWidthSoFar = m_runWidthSoFar;
float lastRoundingWidth = m_finalRoundingWidth;
FloatRect bounds;
const SimpleFontData* primaryFont = m_font->primaryFont();
const SimpleFontData* lastFontData = primaryFont;
......@@ -175,6 +182,12 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
}
}
if (m_accountForGlyphBounds) {
bounds = fontData->boundsForGlyph(glyph);
if (!currentCharacter)
m_firstGlyphOverflow = max<float>(0, -bounds.x());
}
// Advance past the character we just dealt with.
cp += clusterLength;
currentCharacter += clusterLength;
......@@ -205,6 +218,12 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
lastRoundingWidth = width - oldWidth;
if (m_accountForGlyphBounds) {
m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.bottom());
m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, bounds.y());
m_lastGlyphOverflow = max<float>(0, bounds.right() - width);
}
}
m_currentCharacter = currentCharacter;
......
......@@ -33,11 +33,16 @@ class SimpleFontData;
class TextRun;
struct WidthIterator {
WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0);
WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, bool accountForGlyphBounds = false);
void advance(int to, GlyphBuffer* = 0);
bool advanceOneCharacter(float& width, GlyphBuffer* = 0);
float maxGlyphBoundingBoxY() const { ASSERT(m_accountForGlyphBounds); return m_maxGlyphBoundingBoxY; }
float minGlyphBoundingBoxY() const { ASSERT(m_accountForGlyphBounds); return m_minGlyphBoundingBoxY; }
float firstGlyphOverflow() const { ASSERT(m_accountForGlyphBounds); return m_firstGlyphOverflow; }
float lastGlyphOverflow() const { ASSERT(m_accountForGlyphBounds); return m_lastGlyphOverflow; }
const Font* m_font;
const TextRun& m_run;
......@@ -51,7 +56,13 @@ struct WidthIterator {
private:
UChar32 normalizeVoicingMarks(int currentCharacter);
HashSet<const SimpleFontData*>* m_fallbackFonts;
bool m_accountForGlyphBounds;
float m_maxGlyphBoundingBoxY;
float m_minGlyphBoundingBoxY;
float m_firstGlyphOverflow;
float m_lastGlyphOverflow;
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment