Commit ac4d45dd authored by bashi@chromium.org's avatar bashi@chromium.org

[Chromium] Implement font shaping with font-feature-settings on Windows

https://bugs.webkit.org/show_bug.cgi?id=65904

Reviewed by Kenneth Russell.

Source/WebCore:

Use Uniscribe's OpenType APIs to shape complex text to support -webkit-font-feature-settings property.

No new tests. css3/font-feature-settings-rendering.html should pass by this patch.

* platform/graphics/chromium/UniscribeHelper.cpp:
(WebCore::loadOpenTypeFunctions):
(WebCore::UniscribeHelper::UniscribeHelper): Calls loadOpenTypeFunctions if needed.
(WebCore::UniscribeHelper::fillRuns): Uses ScriptItemizeOpenType() if possible.
(WebCore::UniscribeHelper::shape): Uses ScriptShapeOpenType() if possible.
(WebCore::UniscribeHelper::fillShapes): Adds OpenType script tag as an argument.
(WebCore::convertFeatureTag): Added.
(WebCore::UniscribeHelper::setRangeProperties): Added.
* platform/graphics/chromium/UniscribeHelper.h:
* platform/graphics/chromium/UniscribeHelperTextRun.cpp:
(WebCore::UniscribeHelperTextRun::UniscribeHelperTextRun): Calls setRangeProperties().

LayoutTests:

Adds expectations of css3/font-feature-settings-rendering.html for Chromium win port. Since Uniscirbe OpenType APIs are not available on WinXP by default, the test could fail on WinXP.

* platform/chromium-win/css3/font-feature-settings-rendering-expected.png: Added.
* platform/chromium-win/css3/font-feature-settings-rendering-expected.txt: Added.
* platform/chromium/test_expectations.txt: VISTA and WIN7 should pass css3/font-feature-settings-rendering.html.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@96582 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 57c64d87
2011-10-04 Kenichi Ishibashi <bashi@chromium.org>
[Chromium] Implement font shaping with font-feature-settings on Windows
https://bugs.webkit.org/show_bug.cgi?id=65904
Reviewed by Kenneth Russell.
Adds expectations of css3/font-feature-settings-rendering.html for Chromium win port. Since Uniscirbe OpenType APIs are not available on WinXP by default, the test could fail on WinXP.
* platform/chromium-win/css3/font-feature-settings-rendering-expected.png: Added.
* platform/chromium-win/css3/font-feature-settings-rendering-expected.txt: Added.
* platform/chromium/test_expectations.txt: VISTA and WIN7 should pass css3/font-feature-settings-rendering.html.
2011-10-04 Oliver Varga <voliver@inf.u-szeged.hu>
[Qt] Unreviewed gardening. Update Qt specific expected files after r96498.
layer at (0,0) size 800x600
RenderView at (0,0) size 800x600
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
RenderBlock {P} at (0,0) size 784x40
RenderText {#text} at (0,0) size 783x39
text run at (0,0) width 235: "Test for font-feature-settings property. "
text run at (235,0) width 548: "The first word of the following three words should be displayed like \"WebKit\", while others"
text run at (0,20) width 217: "should be displayed as black boxes."
RenderBlock {DIV} at (0,56) size 784x17
RenderText {#text} at (0,0) size 30x16
text run at (0,0) width 30: "WebKit"
RenderBlock {DIV} at (0,73) size 784x17
RenderText {#text} at (0,0) size 96x16
text run at (0,0) width 96: "WebKit"
RenderBlock {DIV} at (0,90) size 784x17
RenderText {#text} at (0,0) size 96x16
text run at (0,0) width 96: "WebKit"
......@@ -486,6 +486,10 @@ WONTFIX SKIP : fast/js/reparsing-semicolon-insertion.html = FAIL
WONTFIX CPU GPU : platform/chromium/rubberbanding = FAIL
WONTFIX CPU GPU : platform/chromium-gpu/compositing/rubberbanding = IMAGE
// This requires usp10.dll version 1.600 or greater on Windows and
// it isn't installed on XP by default.
WONTFIX XP : css3/font-feature-settings-rendering.html = PASS FAIL
// -----------------------------------------------------------------
// LIGHTTPD
// -----------------------------------------------------------------
......@@ -3476,7 +3480,7 @@ BUGWK65951 WIN DEBUG : webaudio/mixing.html = CRASH
BUGWK65951 LINUX MAC DEBUG : webaudio/mixing.html = CRASH PASS
BUGWK65951 LINUX MAC DEBUG : webaudio/test-basic.html = CRASH PASS
BUGWK63796 MAC WIN : css3/font-feature-settings-rendering.html = MISSING FAIL
BUGWK63796 MAC : css3/font-feature-settings-rendering.html = MISSING FAIL
// New test in r93068
BUGWK66268 MAC CPU-CG : editing/deleting/regional-indicators.html = TEXT
......
2011-10-04 Kenichi Ishibashi <bashi@chromium.org>
[Chromium] Implement font shaping with font-feature-settings on Windows
https://bugs.webkit.org/show_bug.cgi?id=65904
Reviewed by Kenneth Russell.
Use Uniscribe's OpenType APIs to shape complex text to support -webkit-font-feature-settings property.
No new tests. css3/font-feature-settings-rendering.html should pass by this patch.
* platform/graphics/chromium/UniscribeHelper.cpp:
(WebCore::loadOpenTypeFunctions):
(WebCore::UniscribeHelper::UniscribeHelper): Calls loadOpenTypeFunctions if needed.
(WebCore::UniscribeHelper::fillRuns): Uses ScriptItemizeOpenType() if possible.
(WebCore::UniscribeHelper::shape): Uses ScriptShapeOpenType() if possible.
(WebCore::UniscribeHelper::fillShapes): Adds OpenType script tag as an argument.
(WebCore::convertFeatureTag): Added.
(WebCore::UniscribeHelper::setRangeProperties): Added.
* platform/graphics/chromium/UniscribeHelper.h:
* platform/graphics/chromium/UniscribeHelperTextRun.cpp:
(WebCore::UniscribeHelperTextRun::UniscribeHelperTextRun): Calls setRangeProperties().
2011-10-04 Ryuan Choi <ryuan.choi@samsung.com>
[EFL] Implement declared but missing functions.
......@@ -41,6 +41,44 @@
namespace WebCore {
// The function types for ScriptItemizeOpenType() and ScriptShapeOpenType().
// We want to use these functions for OpenType feature support, but we can't
// call them directly because usp10.dll does not always have them.
// Instead, we use GetProcAddress() to check whether we can actually use these
// function. If we can't use these functions, we substitute ScriptItemze() and
// ScriptShape().
typedef HRESULT (WINAPI *ScriptItemizeOpenTypeFunc)(const WCHAR*, int, int,
const SCRIPT_CONTROL*,
const SCRIPT_STATE*,
SCRIPT_ITEM*,
OPENTYPE_TAG*, int*);
typedef HRESULT (WINAPI *ScriptShapeOpenTypeFunc)(HDC, SCRIPT_CACHE*,
SCRIPT_ANALYSIS*,
OPENTYPE_TAG, OPENTYPE_TAG,
int*, TEXTRANGE_PROPERTIES**,
int, const WCHAR*, int, int,
WORD*, SCRIPT_CHARPROP*,
WORD*, SCRIPT_GLYPHPROP*,
int*);
static ScriptItemizeOpenTypeFunc gScriptItemizeOpenTypeFunc = 0;
static ScriptShapeOpenTypeFunc gScriptShapeOpenTypeFunc = 0;
static bool gOpenTypeFunctionsLoaded = false;
static void loadOpenTypeFunctions()
{
HMODULE hModule = GetModuleHandle(L"usp10");
if (hModule) {
gScriptItemizeOpenTypeFunc = reinterpret_cast<ScriptItemizeOpenTypeFunc>(GetProcAddress(hModule, "ScriptItemizeOpenType"));
gScriptShapeOpenTypeFunc = reinterpret_cast<ScriptShapeOpenTypeFunc>(GetProcAddress(hModule, "ScriptShapeOpenType"));
}
if (!gScriptItemizeOpenTypeFunc || !gScriptShapeOpenTypeFunc) {
gScriptItemizeOpenTypeFunc = 0;
gScriptShapeOpenTypeFunc = 0;
}
gOpenTypeFunctionsLoaded = true;
}
// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque
// handle and we can't directly query it to make a new HFONT sharing
// its characteristics (height, style, etc) except for family name.
......@@ -92,6 +130,8 @@ UniscribeHelper::UniscribeHelper(const UChar* input,
{
m_logfont.lfFaceName[0] = 0;
if (!gOpenTypeFunctionsLoaded)
loadOpenTypeFunctions();
}
UniscribeHelper::~UniscribeHelper()
......@@ -418,7 +458,8 @@ WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
void UniscribeHelper::fillRuns()
{
HRESULT hr;
m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS);
m_runs.resize(cUniscribeHelperStackRuns);
m_scriptTags.resize(cUniscribeHelperStackRuns);
SCRIPT_STATE inputState;
inputState.uBidiLevel = m_isRtl;
......@@ -473,10 +514,35 @@ void UniscribeHelper::fillRuns()
// It seems to be doing at least two passes, the first where it puts a
// lot of intermediate data into our items, and the second where it
// collates them.
hr = ScriptItemize(m_input, m_inputLength,
static_cast<int>(m_runs.size()) - 1, &inputControl,
&inputState,
&m_runs[0], &numberOfItems);
if (gScriptItemizeOpenTypeFunc) {
hr = gScriptItemizeOpenTypeFunc(m_input, m_inputLength,
static_cast<int>(m_runs.size()) - 1,
&inputControl, &inputState,
&m_runs[0], &m_scriptTags[0],
&numberOfItems);
if (SUCCEEDED(hr)) {
// Pack consecutive runs, the script tag of which are
// SCRIPT_TAG_UNKNOWN, to reduce the number of runs.
for (int i = 0; i < numberOfItems; ++i) {
if (m_scriptTags[i] == SCRIPT_TAG_UNKNOWN) {
int j = 1;
while (i + j < numberOfItems && m_scriptTags[i + j] == SCRIPT_TAG_UNKNOWN)
++j;
if (--j) {
m_runs.remove(i + 1, j);
m_scriptTags.remove(i + 1, j);
numberOfItems -= j;
}
}
}
m_scriptTags.resize(numberOfItems);
}
} else {
hr = ScriptItemize(m_input, m_inputLength,
static_cast<int>(m_runs.size()) - 1,
&inputControl, &inputState, &m_runs[0],
&numberOfItems);
}
if (SUCCEEDED(hr)) {
m_runs.resize(numberOfItems);
break;
......@@ -488,6 +554,7 @@ void UniscribeHelper::fillRuns()
}
// There was not enough items for it to write into, expand.
m_runs.resize(m_runs.size() * 2);
m_scriptTags.resize(m_runs.size());
}
}
......@@ -495,11 +562,14 @@ bool UniscribeHelper::shape(const UChar* input,
int itemLength,
int numGlyphs,
SCRIPT_ITEM& run,
OPENTYPE_TAG scriptTag,
Shaping& shaping)
{
HFONT hfont = m_hfont;
SCRIPT_CACHE* scriptCache = m_scriptCache;
SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
Vector<SCRIPT_CHARPROP, cUniscribeHelperStackChars> charProps;
Vector<SCRIPT_GLYPHPROP, cUniscribeHelperStackChars> glyphProps;
int ascent = m_ascent;
WORD spaceGlyph = m_spaceGlyph;
HDC tempDC = 0;
......@@ -522,6 +592,8 @@ bool UniscribeHelper::shape(const UChar* input,
shaping.m_logs.resize(itemLength);
shaping.m_glyphs.resize(numGlyphs);
shaping.m_visualAttributes.resize(numGlyphs);
charProps.resize(itemLength);
glyphProps.resize(numGlyphs);
#ifdef PURIFY
// http://code.google.com/p/chromium/issues/detail?id=5309
......@@ -542,13 +614,23 @@ bool UniscribeHelper::shape(const UChar* input,
ZeroMemory(&shaping.m_glyphs[0],
sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
#endif
// Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
// here. Is that what we want? It will display control characters.
hr = ScriptShape(tempDC, scriptCache, input, itemLength,
numGlyphs, &run.a,
&shaping.m_glyphs[0], &shaping.m_logs[0],
&shaping.m_visualAttributes[0], &generatedGlyphs);
if (gScriptShapeOpenTypeFunc) {
TEXTRANGE_PROPERTIES* rangeProps = m_featureRecords.size() ? &m_rangeProperties : 0;
hr = gScriptShapeOpenTypeFunc(tempDC, scriptCache, &run.a,
scriptTag, 0, &itemLength,
&rangeProps, rangeProps ? 1 : 0,
input, itemLength, numGlyphs,
&shaping.m_logs[0], &charProps[0],
&shaping.m_glyphs[0], &glyphProps[0],
&generatedGlyphs);
} else {
hr = ScriptShape(tempDC, scriptCache, input, itemLength,
numGlyphs, &run.a,
&shaping.m_glyphs[0], &shaping.m_logs[0],
&shaping.m_visualAttributes[0], &generatedGlyphs);
}
if (hr == E_PENDING) {
// Allocate the DC.
tempDC = GetDC(0);
......@@ -645,6 +727,12 @@ bool UniscribeHelper::shape(const UChar* input,
cleanup:
shaping.m_glyphs.resize(generatedGlyphs);
shaping.m_visualAttributes.resize(generatedGlyphs);
// If we use ScriptShapeOpenType(), visual attributes information for each
// characters are stored in |glyphProps[i].sva|.
if (gScriptShapeOpenTypeFunc) {
for (int i = 0; i < generatedGlyphs; ++i)
memcpy(&shaping.m_visualAttributes[i], &glyphProps[i].sva, sizeof(SCRIPT_VISATTR));
}
shaping.m_advance.resize(generatedGlyphs);
shaping.m_offsets.resize(generatedGlyphs);
if (tempDC) {
......@@ -668,11 +756,11 @@ void UniscribeHelper::fillShapes()
itemLength = m_runs[i + 1].iCharPos - startItem;
int numGlyphs;
if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
if (itemLength < cUniscribeHelperStackChars) {
// We'll start our buffer sizes with the current stack space
// available in our buffers if the current input fits. As long as
// it doesn't expand past that we'll save a lot of time mallocing.
numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
numGlyphs = cUniscribeHelperStackChars;
} else {
// When the input doesn't fit, give up with the stack since it will
// almost surely not be enough room (unless the input actually
......@@ -685,7 +773,7 @@ void UniscribeHelper::fillShapes()
// Convert a string to a glyph string trying the primary font, fonts in
// the fallback list and then script-specific last resort font.
Shaping& shaping = m_shapes[i];
if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], m_scriptTags[i], shaping))
continue;
// At the moment, the only time m_disableFontFallback is set is
......@@ -724,6 +812,7 @@ void UniscribeHelper::fillShapes()
// Some error we don't know how to handle. Nuke all of our data
// since we can't deal with partially valid data later.
m_runs.clear();
m_scriptTags.clear();
m_shapes.clear();
m_screenOrder.clear();
}
......@@ -932,5 +1021,25 @@ bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping,
return false;
}
static OPENTYPE_TAG convertFeatureTag(const String& tag)
{
return ((tag[0] & 0xFF) | ((tag[1] & 0xFF) << 8) | ((tag[2] & 0xFF) << 16) | ((tag[3] & 0xFF) << 24));
}
void UniscribeHelper::setRangeProperties(const FontFeatureSettings* featureSettings)
{
if (!featureSettings || !featureSettings->size()) {
m_featureRecords.resize(0);
return;
}
m_featureRecords.resize(featureSettings->size());
for (unsigned i = 0; i < featureSettings->size(); ++i) {
m_featureRecords[i].lParameter = featureSettings->at(i).value();
m_featureRecords[i].tagFeature = convertFeatureTag(featureSettings->at(i).tag());
}
m_rangeProperties.potfRecords = &m_featureRecords[0];
m_rangeProperties.cotfRecords = m_featureRecords.size();
}
} // namespace WebCore
......@@ -44,10 +44,12 @@ class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper.
namespace WebCore {
class FontFeatureSettings;
class GraphicsContext;
#define UNISCRIBE_HELPER_STACK_RUNS 8
#define UNISCRIBE_HELPER_STACK_CHARS 32
const unsigned cUniscribeHelperStackRuns = 8;
const unsigned cUniscribeHelperStackChars = 32;
const unsigned cUniscribeHelperFeatures = 4;
// This object should be safe to create & destroy frequently, as long as the
// caller preserves the script_cache when possible (this data may be slow to
......@@ -158,6 +160,10 @@ public:
m_disableFontFallback = true;
}
// Set TEXTRANGE_PROPERTIES structure which contains
// OpenType feature records generated from FontFeatureSettings.
void setRangeProperties(const FontFeatureSettings*);
// You must call this after setting any options but before doing any
// other calls like asking for widths or drawing.
void init()
......@@ -269,7 +275,7 @@ private:
// Glyph indices in the font used to display this item. These indices
// are in screen order.
Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_glyphs;
Vector<WORD, cUniscribeHelperStackChars> m_glyphs;
// For each input character, this tells us the first glyph index it
// generated. This is the only array with size of the input chars.
......@@ -278,20 +284,20 @@ private:
// can generate one glyph, in which case there will be adjacent
// duplicates in this list. One character can also generate multiple
// glyphs, in which case there will be skipped indices in this list.
Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_logs;
Vector<WORD, cUniscribeHelperStackChars> m_logs;
// Flags and such for each glyph.
Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visualAttributes;
Vector<SCRIPT_VISATTR, cUniscribeHelperStackChars> m_visualAttributes;
// Horizontal advances for each glyph listed above, this is basically
// how wide each glyph is.
Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_advance;
Vector<int, cUniscribeHelperStackChars> m_advance;
// This contains glyph offsets, from the nominal position of a glyph.
// It is used to adjust the positions of multiple combining characters
// around/above/below base characters in a context-sensitive manner so
// that they don't bump against each other and the base character.
Vector<GOFFSET, UNISCRIBE_HELPER_STACK_CHARS> m_offsets;
Vector<GOFFSET, cUniscribeHelperStackChars> m_offsets;
// Filled by a call to Justify, this is empty for nonjustified text.
// If nonempty, this contains the array of justify characters for each
......@@ -300,7 +306,7 @@ private:
// This is the same as the advance array, but with extra space added
// for some characters. The difference between a glyph's |justify|
// width and it's |advance| width is the extra space added.
Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_justify;
Vector<int, cUniscribeHelperStackChars> m_justify;
// Sizing information for this run. This treats the entire run as a
// character with a preceeding advance, width, and ending advance. The
......@@ -358,7 +364,7 @@ private:
// by |input| comes from ScriptItemize and is supposed to contain
// characters belonging to a single script aside from characters common to
// all scripts (e.g. space).
bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping&);
bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, OPENTYPE_TAG, Shaping&);
// Gets Windows font data for the next best font to try in the list
// of fonts. When there's no more font available, returns false
......@@ -405,9 +411,10 @@ private:
// Uniscribe breaks the text into Runs. These are one length of text that is
// in one script and one direction. This array is in reading order.
Vector<SCRIPT_ITEM, UNISCRIBE_HELPER_STACK_RUNS> m_runs;
Vector<SCRIPT_ITEM, cUniscribeHelperStackRuns> m_runs;
Vector<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes;
Vector<Shaping, cUniscribeHelperStackRuns> m_shapes;
Vector<OPENTYPE_TAG, cUniscribeHelperStackRuns> m_scriptTags;
// This is a mapping between reading order and screen order for the items.
// Uniscribe's items array are in reading order. For right-to-left text,
......@@ -416,7 +423,12 @@ private:
// and positions. This list is in screen order from left to right, and
// gives the index into the |m_runs| and |m_shapes| arrays of each
// subsequent item.
Vector<int, UNISCRIBE_HELPER_STACK_RUNS> m_screenOrder;
Vector<int, cUniscribeHelperStackRuns> m_screenOrder;
// This contains Uniscribe's OpenType feature settings. This structure
// is filled by using WebKit's |FontFeatureSettings|.
TEXTRANGE_PROPERTIES m_rangeProperties;
Vector<OPENTYPE_FEATURE_RECORD, cUniscribeHelperFeatures> m_featureRecords;
};
} // namespace WebCore
......
......@@ -53,6 +53,7 @@ UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
setSpaceWidth(font.spaceWidth());
setWordSpacing(font.wordSpacing());
setAscent(font.fontMetrics().ascent());
setRangeProperties(font.fontDescription().featureSettings());
init();
......
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