Index: webkit/port/platform/graphics/UniscribeHelper.cpp |
=================================================================== |
--- webkit/port/platform/graphics/UniscribeHelper.cpp (revision 5490) |
+++ webkit/port/platform/graphics/UniscribeHelper.cpp (working copy) |
@@ -2,21 +2,23 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include "config.h" |
+#include "UniscribeHelper.h" |
+ |
#include <windows.h> |
-#include "base/gfx/uniscribe.h" |
+#include "FontUtilsWin.h" |
+#include "wtf/Assertions.h" |
-#include "base/gfx/font_utils.h" |
-#include "base/logging.h" |
+namespace WebCore { |
-namespace gfx { |
- |
// This function is used to see where word spacing should be applied inside |
// runs. Note that this must match Font::treatAsSpace so we all agree where |
// and how much space this is, so we don't want to do more general Unicode |
// "is this a word break" thing. |
-static bool TreatAsSpace(wchar_t c) { |
- return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; |
+static bool TreatAsSpace(UChar c) |
+{ |
+ return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; |
} |
// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid |
@@ -27,14 +29,16 @@ |
// sure that the text run is rendered successfully. |
static bool ContainsMissingGlyphs(WORD *glyphs, |
int length, |
- SCRIPT_FONTPROPERTIES* properties) { |
- for (int i = 0; i < length; ++i) { |
- if (glyphs[i] == properties->wgDefault || |
- (glyphs[i] == properties->wgInvalid && glyphs[i] != properties->wgBlank)) |
- return true; |
- } |
+ SCRIPT_FONTPROPERTIES* properties) |
+{ |
+ for (int i = 0; i < length; ++i) { |
+ if (glyphs[i] == properties->wgDefault || |
+ (glyphs[i] == properties->wgInvalid && |
+ glyphs[i] != properties->wgBlank)) |
+ return true; |
+ } |
- return false; |
+ return false; |
} |
// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque |
@@ -43,806 +47,822 @@ |
// This function uses GetObject to convert HFONT back to LOGFONT, |
// resets the fields of LOGFONT and calculates style to use later |
// for the creation of a font identical to HFONT other than family name. |
-static void SetLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style) { |
- DCHECK(hfont && logfont); |
- if (!hfont || !logfont) |
- return; |
+static void SetLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style) |
+{ |
+ ASSERT(hfont && logfont); |
+ if (!hfont || !logfont) |
+ return; |
- GetObject(hfont, sizeof(LOGFONT), logfont); |
- // We reset these fields to values appropriate for CreateFontIndirect. |
- // while keeping lfHeight, which is the most important value in creating |
- // a new font similar to hfont. |
- logfont->lfWidth = 0; |
- logfont->lfEscapement = 0; |
- logfont->lfOrientation = 0; |
- logfont->lfCharSet = DEFAULT_CHARSET; |
- logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; |
- logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings. |
- logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
- if (style) |
- *style = gfx::GetStyleFromLogfont(logfont); |
+ GetObject(hfont, sizeof(LOGFONT), logfont); |
+ // We reset these fields to values appropriate for CreateFontIndirect. |
+ // while keeping lfHeight, which is the most important value in creating |
+ // a new font similar to hfont. |
+ logfont->lfWidth = 0; |
+ logfont->lfEscapement = 0; |
+ logfont->lfOrientation = 0; |
+ logfont->lfCharSet = DEFAULT_CHARSET; |
+ logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; |
+ logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings. |
+ logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
+ if (style) |
+ *style = GetStyleFromLogfont(logfont); |
} |
-UniscribeState::UniscribeState(const wchar_t* input, |
- int input_length, |
- bool is_rtl, |
- HFONT hfont, |
- SCRIPT_CACHE* script_cache, |
- SCRIPT_FONTPROPERTIES* font_properties) |
- : input_(input), |
- input_length_(input_length), |
- is_rtl_(is_rtl), |
- hfont_(hfont), |
- script_cache_(script_cache), |
- font_properties_(font_properties), |
- directional_override_(false), |
- inhibit_ligate_(false), |
- letter_spacing_(0), |
- space_width_(0), |
- word_spacing_(0), |
- ascent_(0) { |
- logfont_.lfFaceName[0] = 0; |
+UniscribeHelper::UniscribeHelper(const UChar* input, |
+ int inputLength, |
+ bool isRtl, |
+ HFONT hfont, |
+ SCRIPT_CACHE* scriptCache, |
+ SCRIPT_FONTPROPERTIES* fontProperties) |
+ : m_input(input) |
+ , m_inputLength(inputLength) |
+ , m_isRtl(isRtl) |
+ , m_hfont(hfont) |
+ , m_scriptCache(scriptCache) |
+ , m_fontProperties(fontProperties) |
+ , m_directionalOverride(false) |
+ , m_inhibitLigate(false) |
+ , m_letterSpacing(0) |
+ , m_spaceWidth(0) |
+ , m_wordSpacing(0) |
+ , m_ascent(0) |
+{ |
+ m_logfont.lfFaceName[0] = 0; |
} |
-UniscribeState::~UniscribeState() { |
+UniscribeHelper::~UniscribeHelper() |
+{ |
} |
-void UniscribeState::InitWithOptionalLengthProtection(bool length_protection) { |
- // We cap the input length and just don't do anything. We'll allocate a lot |
- // of things of the size of the number of characters, so the allocated memory |
- // will be several times the input length. Plus shaping such a large buffer |
- // may be a form of denial of service. No legitimate text should be this long. |
- // It also appears that Uniscribe flatly rejects very long strings, so we |
- // don't lose anything by doing this. |
- // |
- // The input length protection may be disabled by the unit tests to cause |
- // an error condition. |
- static const int kMaxInputLength = 65535; |
- if (input_length_ == 0 || |
- (length_protection && input_length_ > kMaxInputLength)) |
- return; |
+void UniscribeHelper::InitWithOptionalLengthProtection(bool lengthProtection) |
+{ |
+ // We cap the input length and just don't do anything. We'll allocate a lot |
+ // of things of the size of the number of characters, so the allocated |
+ // memory will be several times the input length. Plus shaping such a large |
+ // buffer may be a form of denial of service. No legitimate text should be |
+ // this long. It also appears that Uniscribe flatly rejects very long |
+ // strings, so we don't lose anything by doing this. |
+ // |
+ // The input length protection may be disabled by the unit tests to cause |
+ // an error condition. |
+ static const int kMaxInputLength = 65535; |
+ if (m_inputLength == 0 || |
+ (lengthProtection && m_inputLength > kMaxInputLength)) |
+ return; |
- FillRuns(); |
- FillShapes(); |
- FillScreenOrder(); |
+ FillRuns(); |
+ FillShapes(); |
+ FillScreenOrder(); |
} |
-int UniscribeState::Width() const { |
- int width = 0; |
- for (int item_index = 0; item_index < static_cast<int>(runs_->size()); |
- item_index++) { |
- width += AdvanceForItem(item_index); |
- } |
- return width; |
+int UniscribeHelper::Width() const |
+{ |
+ int width = 0; |
+ for (int item_index = 0; item_index < static_cast<int>(m_runs.size()); |
+ item_index++) { |
+ width += AdvanceForItem(item_index); |
+ } |
+ return width; |
} |
-void UniscribeState::Justify(int additional_space) { |
- // Count the total number of glyphs we have so we know how big to make the |
- // buffers below. |
- int total_glyphs = 0; |
- for (size_t run = 0; run < runs_->size(); run++) { |
- int run_idx = screen_order_[run]; |
- total_glyphs += static_cast<int>(shapes_[run_idx].glyph_length()); |
- } |
- if (total_glyphs == 0) |
- return; // Nothing to do. |
+void UniscribeHelper::Justify(int additionalSpace) |
+{ |
+ // Count the total number of glyphs we have so we know how big to make the |
+ // buffers below. |
+ int totalGlyphs = 0; |
+ for (size_t run = 0; run < m_runs.size(); run++) { |
+ int run_idx = m_screenOrder[run]; |
+ totalGlyphs += static_cast<int>(m_shapes[run_idx].glyphLength()); |
+ } |
+ if (totalGlyphs == 0) |
+ return; // Nothing to do. |
- // We make one big buffer in screen order of all the glyphs we are drawing |
- // across runs so that the justification function will adjust evenly across |
- // all glyphs. |
- StackVector<SCRIPT_VISATTR, 64> visattr; |
- visattr->resize(total_glyphs); |
- StackVector<int, 64> advances; |
- advances->resize(total_glyphs); |
- StackVector<int, 64> justify; |
- justify->resize(total_glyphs); |
+ // We make one big buffer in screen order of all the glyphs we are drawing |
+ // across runs so that the justification function will adjust evenly across |
+ // all glyphs. |
+ Vector<SCRIPT_VISATTR, 64> visattr; |
+ visattr.resize(totalGlyphs); |
+ Vector<int, 64> advances; |
+ advances.resize(totalGlyphs); |
+ Vector<int, 64> justify; |
+ justify.resize(totalGlyphs); |
- // Build the packed input. |
- int dest_index = 0; |
- for (size_t run = 0; run < runs_->size(); run++) { |
- int run_idx = screen_order_[run]; |
- const Shaping& shaping = shapes_[run_idx]; |
+ // Build the packed input. |
+ int dest_index = 0; |
+ for (size_t run = 0; run < m_runs.size(); run++) { |
+ int run_idx = m_screenOrder[run]; |
+ const Shaping& shaping = m_shapes[run_idx]; |
- for (int i = 0; i < shaping.glyph_length(); i++, dest_index++) { |
- memcpy(&visattr[dest_index], &shaping.visattr[i], sizeof(SCRIPT_VISATTR)); |
- advances[dest_index] = shaping.advance[i]; |
+ for (int i = 0; i < shaping.glyphLength(); i++, dest_index++) { |
+ memcpy(&visattr[dest_index], &shaping.m_visattr[i], |
+ sizeof(SCRIPT_VISATTR)); |
+ advances[dest_index] = shaping.m_advance[i]; |
+ } |
} |
- } |
- // The documentation for ScriptJustify is wrong, the parameter is the space |
- // to add and not the width of the column you want. |
- const int min_kashida = 1; // How do we decide what this should be? |
- ScriptJustify(&visattr[0], &advances[0], total_glyphs, additional_space, |
- min_kashida, &justify[0]); |
+ // The documentation for ScriptJustify is wrong, the parameter is the space |
+ // to add and not the width of the column you want. |
+ const int minKashida = 1; // How do we decide what this should be? |
+ ScriptJustify(&visattr[0], &advances[0], totalGlyphs, additionalSpace, |
+ minKashida, &justify[0]); |
- // Now we have to unpack the justification amounts back into the runs so |
- // the glyph indices match. |
- int global_glyph_index = 0; |
- for (size_t run = 0; run < runs_->size(); run++) { |
- int run_idx = screen_order_[run]; |
- Shaping& shaping = shapes_[run_idx]; |
+ // Now we have to unpack the justification amounts back into the runs so |
+ // the glyph indices match. |
+ int globalGlyphIndex = 0; |
+ for (size_t run = 0; run < m_runs.size(); run++) { |
+ int run_idx = m_screenOrder[run]; |
+ Shaping& shaping = m_shapes[run_idx]; |
- shaping.justify->resize(shaping.glyph_length()); |
- for (int i = 0; i < shaping.glyph_length(); i++, global_glyph_index++) |
- shaping.justify[i] = justify[global_glyph_index]; |
- } |
+ shaping.m_justify.resize(shaping.glyphLength()); |
+ for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++) |
+ shaping.m_justify[i] = justify[globalGlyphIndex]; |
+ } |
} |
-int UniscribeState::CharacterToX(int offset) const { |
- HRESULT hr; |
- DCHECK(offset <= input_length_); |
+int UniscribeHelper::CharacterToX(int offset) const |
+{ |
+ HRESULT hr; |
+ ASSERT(offset <= m_inputLength); |
- // Our algorithm is to traverse the items in screen order from left to |
- // right, adding in each item's screen width until we find the item with |
- // the requested character in it. |
- int width = 0; |
- for (size_t screen_idx = 0; screen_idx < runs_->size(); screen_idx++) { |
- // Compute the length of this run. |
- int item_idx = screen_order_[screen_idx]; |
- const SCRIPT_ITEM& item = runs_[item_idx]; |
- const Shaping& shaping = shapes_[item_idx]; |
- int item_length = shaping.char_length(); |
+ // Our algorithm is to traverse the items in screen order from left to |
+ // right, adding in each item's screen width until we find the item with |
+ // the requested character in it. |
+ int width = 0; |
+ for (size_t screen_idx = 0; screen_idx < m_runs.size(); screen_idx++) { |
+ // Compute the length of this run. |
+ int itemIdx = m_screenOrder[screen_idx]; |
+ const SCRIPT_ITEM& item = m_runs[itemIdx]; |
+ const Shaping& shaping = m_shapes[itemIdx]; |
+ int itemLength = shaping.charLength(); |
- if (offset >= item.iCharPos && offset <= item.iCharPos + item_length) { |
- // Character offset is in this run. |
- int char_len = offset - item.iCharPos; |
+ if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) { |
+ // Character offset is in this run. |
+ int char_len = offset - item.iCharPos; |
- int cur_x = 0; |
- hr = ScriptCPtoX(char_len, FALSE, item_length, shaping.glyph_length(), |
- &shaping.logs[0], &shaping.visattr[0], |
- shaping.effective_advances(), &item.a, &cur_x); |
- if (FAILED(hr)) |
- return 0; |
+ int curX = 0; |
+ hr = ScriptCPtoX(char_len, FALSE, itemLength, |
+ shaping.glyphLength(), |
+ &shaping.m_logs[0], &shaping.m_visattr[0], |
+ shaping.effectiveAdvances(), &item.a, &curX); |
+ if (FAILED(hr)) |
+ return 0; |
- width += cur_x + shaping.pre_padding; |
- DCHECK(width >= 0); |
- return width; |
+ width += curX + shaping.m_prePadding; |
+ ASSERT(width >= 0); |
+ return width; |
+ } |
+ |
+ // Move to the next item. |
+ width += AdvanceForItem(itemIdx); |
} |
- |
- // Move to the next item. |
- width += AdvanceForItem(item_idx); |
- } |
- DCHECK(width >= 0); |
- return width; |
+ ASSERT(width >= 0); |
+ return width; |
} |
-int UniscribeState::XToCharacter(int x) const { |
- // We iterate in screen order until we find the item with the given pixel |
- // position in it. When we find that guy, we ask Uniscribe for the |
- // character index. |
- HRESULT hr; |
- for (size_t screen_idx = 0; screen_idx < runs_->size(); screen_idx++) { |
- int item_idx = screen_order_[screen_idx]; |
- int advance_for_item = AdvanceForItem(item_idx); |
+int UniscribeHelper::XToCharacter(int x) const |
+{ |
+ // We iterate in screen order until we find the item with the given pixel |
+ // position in it. When we find that guy, we ask Uniscribe for the |
+ // character index. |
+ HRESULT hr; |
+ for (size_t screen_idx = 0; screen_idx < m_runs.size(); screen_idx++) { |
+ int itemIdx = m_screenOrder[screen_idx]; |
+ int advance_for_item = AdvanceForItem(itemIdx); |
- // Note that the run may be empty if shaping failed, so we want to skip |
- // over it. |
- const Shaping& shaping = shapes_[item_idx]; |
- int item_length = shaping.char_length(); |
- if (x <= advance_for_item && item_length > 0) { |
- // The requested offset is within this item. |
- const SCRIPT_ITEM& item = runs_[item_idx]; |
+ // Note that the run may be empty if shaping failed, so we want to skip |
+ // over it. |
+ const Shaping& shaping = m_shapes[itemIdx]; |
+ int itemLength = shaping.charLength(); |
+ if (x <= advance_for_item && itemLength > 0) { |
+ // The requested offset is within this item. |
+ const SCRIPT_ITEM& item = m_runs[itemIdx]; |
- // Account for the leading space we've added to this run that Uniscribe |
- // doesn't know about. |
- x -= shaping.pre_padding; |
+ // Account for the leading space we've added to this run that |
+ // Uniscribe doesn't know about. |
+ x -= shaping.m_prePadding; |
- int char_x = 0; |
- int trailing; |
- hr = ScriptXtoCP(x, item_length, shaping.glyph_length(), |
- &shaping.logs[0], &shaping.visattr[0], |
- shaping.effective_advances(), &item.a, &char_x, |
- &trailing); |
+ int char_x = 0; |
+ int trailing; |
+ hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(), |
+ &shaping.m_logs[0], &shaping.m_visattr[0], |
+ shaping.effectiveAdvances(), &item.a, &char_x, |
+ &trailing); |
- // The character offset is within the item. We need to add the item's |
- // offset to transform it into the space of the TextRun |
- return char_x + item.iCharPos; |
+ // The character offset is within the item. We need to add the |
+ // item's offset to transform it into the space of the TextRun |
+ return char_x + item.iCharPos; |
+ } |
+ |
+ // The offset is beyond this item, account for its length and move on. |
+ x -= advance_for_item; |
} |
- // The offset is beyond this item, account for its length and move on. |
- x -= advance_for_item; |
- } |
- |
- // Error condition, we don't know what to do if we don't have that X |
- // position in any of our items. |
- return 0; |
+ // Error condition, we don't know what to do if we don't have that X |
+ // position in any of our items. |
+ return 0; |
} |
-void UniscribeState::Draw(HDC dc, int x, int y, int from, int to) { |
- HGDIOBJ old_font = 0; |
- int cur_x = x; |
- bool first_run = true; |
+void UniscribeHelper::Draw(HDC dc, int x, int y, int from, int to) |
+{ |
+ HGDIOBJ oldFont = 0; |
+ int curX = x; |
+ bool firstRun = true; |
- for (size_t screen_idx = 0; screen_idx < runs_->size(); screen_idx++) { |
- int item_idx = screen_order_[screen_idx]; |
- const SCRIPT_ITEM& item = runs_[item_idx]; |
- const Shaping& shaping = shapes_[item_idx]; |
+ for (size_t screen_idx = 0; screen_idx < m_runs.size(); screen_idx++) { |
+ int itemIdx = m_screenOrder[screen_idx]; |
+ const SCRIPT_ITEM& item = m_runs[itemIdx]; |
+ const Shaping& shaping = m_shapes[itemIdx]; |
- // Character offsets within this run. THESE MAY NOT BE IN RANGE and may |
- // be negative, etc. The code below handles this. |
- int from_char = from - item.iCharPos; |
- int to_char = to - item.iCharPos; |
+ // Character offsets within this run. THESE MAY NOT BE IN RANGE and may |
+ // be negative, etc. The code below handles this. |
+ int fromChar = from - item.iCharPos; |
+ int to_char = to - item.iCharPos; |
- // See if we need to draw any characters in this item. |
- if (shaping.char_length() == 0 || |
- from_char >= shaping.char_length() || to_char <= 0) { |
- // No chars in this item to display. |
- cur_x += AdvanceForItem(item_idx); |
- continue; |
- } |
+ // See if we need to draw any characters in this item. |
+ if (shaping.charLength() == 0 || |
+ fromChar >= shaping.charLength() || to_char <= 0) { |
+ // No chars in this item to display. |
+ curX += AdvanceForItem(itemIdx); |
+ continue; |
+ } |
- // Compute the starting glyph within this span. |from| and |to| are |
- // global offsets that may intersect arbitrarily with our local run. |
- int from_glyph, after_glyph; |
- if (item.a.fRTL) { |
- // To compute the first glyph when going RTL, we use |to|. |
- if (to_char >= shaping.char_length()) { |
- // The end of the text is after (to the left) of us. |
- from_glyph = 0; |
- } else { |
- // Since |to| is exclusive, the first character we draw on the left |
- // is actually the one right before (to the right) of |to|. |
- from_glyph = shaping.logs[to_char - 1]; |
- } |
+ // Compute the starting glyph within this span. |from| and |to| are |
+ // global offsets that may intersect arbitrarily with our local run. |
+ int fromGlyph, afterGlyph; |
+ if (item.a.fRTL) { |
+ // To compute the first glyph when going RTL, we use |to|. |
+ if (to_char >= shaping.charLength()) { |
+ // The end of the text is after (to the left) of us. |
+ fromGlyph = 0; |
+ } else { |
+ // Since |to| is exclusive, the first character we draw on the |
+ // left is actually the one right before (to the right) of |
+ // |to|. |
+ fromGlyph = shaping.m_logs[to_char - 1]; |
+ } |
- // The last glyph is actually the first character in the range. |
- if (from_char <= 0) { |
- // The first character to draw is before (to the right) of this span, |
- // so draw all the way to the end. |
- after_glyph = shaping.glyph_length(); |
- } else { |
- // We want to draw everything up until the character to the right of |
- // |from|. To the right is - 1, so we look that up (remember our |
- // character could be more than one glyph, so we can't look up our |
- // glyph and add one). |
- after_glyph = shaping.logs[from_char - 1]; |
- } |
- } else { |
- // Easy case, everybody agrees about directions. We only need to handle |
- // boundary conditions to get a range inclusive at the beginning, and |
- // exclusive at the ending. We have to do some computation to see the |
- // glyph one past the end. |
- from_glyph = shaping.logs[from_char < 0 ? 0 : from_char]; |
- if (to_char >= shaping.char_length()) |
- after_glyph = shaping.glyph_length(); |
- else |
- after_glyph = shaping.logs[to_char]; |
- } |
+ // The last glyph is actually the first character in the range. |
+ if (fromChar <= 0) { |
+ // The first character to draw is before (to the right) of this |
+ // span, so draw all the way to the end. |
+ afterGlyph = shaping.glyphLength(); |
+ } else { |
+ // We want to draw everything up until the character to the |
+ // right of |from|. To the right is - 1, so we look that up |
+ // (remember our character could be more than one glyph, so we |
+ // can't look up our glyph and add one). |
+ afterGlyph = shaping.m_logs[fromChar - 1]; |
+ } |
+ } else { |
+ // Easy case, everybody agrees about directions. We only need to |
+ // handle boundary conditions to get a range inclusive at the |
+ // beginning, and exclusive at the ending. We have to do some |
+ // computation to see the glyph one past the end. |
+ fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar]; |
+ if (to_char >= shaping.charLength()) |
+ afterGlyph = shaping.glyphLength(); |
+ else |
+ afterGlyph = shaping.m_logs[to_char]; |
+ } |
- // Account for the characters that were skipped in this run. When |
- // WebKit asks us to draw a subset of the run, it actually tells us |
- // to draw at the X offset of the beginning of the run, since it |
- // doesn't know the internal position of any of our characters. |
- const int* effective_advances = shaping.effective_advances(); |
- int inner_offset = 0; |
- for (int i = 0; i < from_glyph; i++) |
- inner_offset += effective_advances[i]; |
+ // Account for the characters that were skipped in this run. When |
+ // WebKit asks us to draw a subset of the run, it actually tells us |
+ // to draw at the X offset of the beginning of the run, since it |
+ // doesn't know the internal position of any of our characters. |
+ const int* effectiveAdvances = shaping.effectiveAdvances(); |
+ int innerOffset = 0; |
+ for (int i = 0; i < fromGlyph; i++) |
+ innerOffset += effectiveAdvances[i]; |
- // Actually draw the glyphs we found. |
- int glyph_count = after_glyph - from_glyph; |
- if (from_glyph >= 0 && glyph_count > 0) { |
- // Account for the preceeding space we need to add to this run. We don't |
- // need to count for the following space because that will be counted |
- // in AdvanceForItem below when we move to the next run. |
- inner_offset += shaping.pre_padding; |
+ // Actually draw the glyphs we found. |
+ int glyphCount = afterGlyph - fromGlyph; |
+ if (fromGlyph >= 0 && glyphCount > 0) { |
+ // Account for the preceeding space we need to add to this run. We |
+ // don't need to count for the following space because that will be |
+ // counted in AdvanceForItem below when we move to the next run. |
+ innerOffset += shaping.m_prePadding; |
- // Pass NULL in when there is no justification. |
- const int* justify = shaping.justify->empty() ? |
- NULL : &shaping.justify[from_glyph]; |
+ // Pass NULL in when there is no justification. |
+ const int* justify = shaping.m_justify.size() == 0 ? |
+ NULL : &shaping.m_justify[fromGlyph]; |
- if (first_run) { |
- old_font = SelectObject(dc, shaping.hfont_); |
- first_run = false; |
- } else { |
- SelectObject(dc, shaping.hfont_); |
- } |
+ if (firstRun) { |
+ oldFont = SelectObject(dc, shaping.m_hfont); |
+ firstRun = false; |
+ } else { |
+ SelectObject(dc, shaping.m_hfont); |
+ } |
- // TODO(brettw) bug 698452: if a half a character is selected, |
- // we should set up a clip rect so we draw the half of the glyph |
- // correctly. |
- // Fonts with different ascents can be used to render different runs. |
- // 'Across-runs' y-coordinate correction needs to be adjusted |
- // for each font. |
- HRESULT hr = S_FALSE; |
- for (int executions = 0; executions < 2; ++executions) { |
- hr = ScriptTextOut(dc, shaping.script_cache_, cur_x + inner_offset, |
- y - shaping.ascent_offset_, 0, NULL, &item.a, NULL, |
- 0, &shaping.glyphs[from_glyph], |
- glyph_count, &shaping.advance[from_glyph], |
- justify, &shaping.offsets[from_glyph]); |
- if (S_OK != hr && 0 == executions) { |
- // If this ScriptTextOut is called from the renderer it might fail |
- // because the sandbox is preventing it from opening the font files. |
- // If we are running in the renderer, TryToPreloadFont is overridden |
- // to ask the browser to preload the font for us so we can access it. |
- TryToPreloadFont(shaping.hfont_); |
- continue; |
+ // TODO(brettw) bug 698452: if a half a character is selected, |
+ // we should set up a clip rect so we draw the half of the glyph |
+ // correctly. |
+ // Fonts with different ascents can be used to render different |
+ // runs. 'Across-runs' y-coordinate correction needs to be |
+ // adjusted for each font. |
+ HRESULT hr = S_FALSE; |
+ for (int executions = 0; executions < 2; ++executions) { |
+ hr = ScriptTextOut(dc, shaping.m_scriptCache, |
+ curX + innerOffset, |
+ y - shaping.m_ascentOffset, |
+ 0, NULL, &item.a, NULL, 0, |
+ &shaping.m_glyphs[fromGlyph], |
+ glyphCount, |
+ &shaping.m_advance[fromGlyph], |
+ justify, |
+ &shaping.m_offsets[fromGlyph]); |
+ if (S_OK != hr && 0 == executions) { |
+ // If this ScriptTextOut is called from the renderer it |
+ // might fail because the sandbox is preventing it from |
+ // opening the font files. If we are running in the |
+ // renderer, TryToPreloadFont is overridden to ask the |
+ // browser to preload the font for us so we can access it. |
+ TryToPreloadFont(shaping.m_hfont); |
+ continue; |
+ } |
+ break; |
+ } |
+ |
+ ASSERT(S_OK == hr); |
} |
- break; |
- } |
- DCHECK(S_OK == hr); |
- |
- |
+ curX += AdvanceForItem(itemIdx); |
} |
- cur_x += AdvanceForItem(item_idx); |
- } |
- |
- if (old_font) |
- SelectObject(dc, old_font); |
+ if (oldFont) |
+ SelectObject(dc, oldFont); |
} |
-WORD UniscribeState::FirstGlyphForCharacter(int char_offset) const { |
- // Find the run for the given character. |
- for (int i = 0; i < static_cast<int>(runs_->size()); i++) { |
- int first_char = runs_[i].iCharPos; |
- const Shaping& shaping = shapes_[i]; |
- int local_offset = char_offset - first_char; |
- if (local_offset >= 0 && local_offset < shaping.char_length()) { |
- // The character is in this run, return the first glyph for it (should |
- // generally be the only glyph). It seems Uniscribe gives glyph 0 for |
- // empty, which is what we want to return in the "missing" case. |
- size_t glyph_index = shaping.logs[local_offset]; |
- if (glyph_index >= shaping.glyphs->size()) { |
- // The glyph should be in this run, but the run has too few actual |
- // characters. This can happen when shaping the run fails, in which |
- // case, we should have no data in the logs at all. |
- DCHECK(shaping.glyphs->empty()); |
- return 0; |
- } |
- return shaping.glyphs[glyph_index]; |
+WORD UniscribeHelper::FirstGlyphForCharacter(int charOffset) const |
+{ |
+ // Find the run for the given character. |
+ for (int i = 0; i < static_cast<int>(m_runs.size()); i++) { |
+ int firstChar = m_runs[i].iCharPos; |
+ const Shaping& shaping = m_shapes[i]; |
+ int localOffset = charOffset - firstChar; |
+ if (localOffset >= 0 && localOffset < shaping.charLength()) { |
+ // The character is in this run, return the first glyph for it |
+ // (should generally be the only glyph). It seems Uniscribe gives |
+ // glyph 0 for empty, which is what we want to return in the |
+ // "missing" case. |
+ size_t glyphIndex = shaping.m_logs[localOffset]; |
+ if (glyphIndex >= shaping.m_glyphs.size()) { |
+ // The glyph should be in this run, but the run has too few |
+ // actual characters. This can happen when shaping the run |
+ // fails, in which case, we should have no data in the logs at |
+ // all. |
+ ASSERT(shaping.m_glyphs.size() == 0); |
+ return 0; |
+ } |
+ return shaping.m_glyphs[glyphIndex]; |
+ } |
} |
- } |
- return 0; |
+ return 0; |
} |
-void UniscribeState::FillRuns() { |
- HRESULT hr; |
- runs_->resize(UNISCRIBE_STATE_STACK_RUNS); |
+void UniscribeHelper::FillRuns() |
+{ |
+ HRESULT hr; |
+ m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS); |
- SCRIPT_STATE input_state; |
- input_state.uBidiLevel = is_rtl_; |
- input_state.fOverrideDirection = directional_override_; |
- input_state.fInhibitSymSwap = false; |
- input_state.fCharShape = false; // Not implemented in Uniscribe |
- input_state.fDigitSubstitute = false; // Do we want this for Arabic? |
- input_state.fInhibitLigate = inhibit_ligate_; |
- input_state.fDisplayZWG = false; // Don't draw control characters. |
- input_state.fArabicNumContext = is_rtl_; // Do we want this for Arabic? |
- input_state.fGcpClusters = false; |
- input_state.fReserved = 0; |
- input_state.fEngineReserved = 0; |
- // The psControl argument to ScriptItemize should be non-NULL for RTL text, |
- // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a |
- // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the |
- // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx . |
- static SCRIPT_CONTROL input_control = {0, // uDefaultLanguage :16; |
- 0, // fContextDigits :1; |
- 0, // fInvertPreBoundDir :1; |
- 0, // fInvertPostBoundDir :1; |
- 0, // fLinkStringBefore :1; |
- 0, // fLinkStringAfter :1; |
- 0, // fNeutralOverride :1; |
- 0, // fNumericOverride :1; |
- 0, // fLegacyBidiClass :1; |
- 0, // fMergeNeutralItems :1; |
- 0};// fReserved :7; |
- // Calling ScriptApplyDigitSubstitution( NULL, &input_control, &input_state) |
- // here would be appropriate if we wanted to set the language ID, and get |
- // local digit substitution behavior. For now, don't do it. |
+ SCRIPT_STATE inputState; |
+ inputState.uBidiLevel = m_isRtl; |
+ inputState.fOverrideDirection = m_directionalOverride; |
+ inputState.fInhibitSymSwap = false; |
+ inputState.fCharShape = false; // Not implemented in Uniscribe |
+ inputState.fDigitSubstitute = false; // Do we want this for Arabic? |
+ inputState.fInhibitLigate = m_inhibitLigate; |
+ inputState.fDisplayZWG = false; // Don't draw control characters. |
+ inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic? |
+ inputState.fGcpClusters = false; |
+ inputState.fReserved = 0; |
+ inputState.fEngineReserved = 0; |
+ // The psControl argument to ScriptItemize should be non-NULL for RTL text, |
+ // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a |
+ // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the |
+ // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx |
+ static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16; |
+ 0, // fContextDigits :1; |
+ 0, // fInvertPreBoundDir :1; |
+ 0, // fInvertPostBoundDir :1; |
+ 0, // fLinkStringBefore :1; |
+ 0, // fLinkStringAfter :1; |
+ 0, // fNeutralOverride :1; |
+ 0, // fNumericOverride :1; |
+ 0, // fLegacyBidiClass :1; |
+ 0, // fMergeNeutralItems :1; |
+ 0};// fReserved :7; |
+ // Calling ScriptApplyDigitSubstitution( NULL, &inputControl, &inputState) |
+ // here would be appropriate if we wanted to set the language ID, and get |
+ // local digit substitution behavior. For now, don't do it. |
- while (true) { |
- int num_items = 0; |
+ while (true) { |
+ int num_items = 0; |
- // Ideally, we would have a way to know the runs before and after this |
- // one, and put them into the control parameter of ScriptItemize. This |
- // would allow us to shape characters properly that cross style |
- // boundaries (WebKit bug 6148). |
- // |
- // We tell ScriptItemize that the output list of items is one smaller |
- // than it actually is. According to Mozilla bug 366643, if there is |
- // not enough room in the array on pre-SP2 systems, ScriptItemize will |
- // write one past the end of the buffer. |
- // |
- // ScriptItemize is very strange. It will often require a much larger |
- // ITEM buffer internally than it will give us as output. For example, |
- // it will say a 16-item buffer is not big enough, and will write |
- // interesting numbers into all those items. But when we give it a 32 |
- // item buffer and it succeeds, it only has one item output. |
- // |
- // 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(input_, input_length_, |
- static_cast<int>(runs_->size()) - 1, &input_control, &input_state, |
- &runs_[0], &num_items); |
- if (SUCCEEDED(hr)) { |
- runs_->resize(num_items); |
- break; |
+ // Ideally, we would have a way to know the runs before and after this |
+ // one, and put them into the control parameter of ScriptItemize. This |
+ // would allow us to shape characters properly that cross style |
+ // boundaries (WebKit bug 6148). |
+ // |
+ // We tell ScriptItemize that the output list of items is one smaller |
+ // than it actually is. According to Mozilla bug 366643, if there is |
+ // not enough room in the array on pre-SP2 systems, ScriptItemize will |
+ // write one past the end of the buffer. |
+ // |
+ // ScriptItemize is very strange. It will often require a much larger |
+ // ITEM buffer internally than it will give us as output. For example, |
+ // it will say a 16-item buffer is not big enough, and will write |
+ // interesting numbers into all those items. But when we give it a 32 |
+ // item buffer and it succeeds, it only has one item output. |
+ // |
+ // 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], &num_items); |
+ if (SUCCEEDED(hr)) { |
+ m_runs.resize(num_items); |
+ break; |
+ } |
+ if (hr != E_OUTOFMEMORY) { |
+ // Some kind of unexpected error. |
+ m_runs.resize(0); |
+ break; |
+ } |
+ // There was not enough items for it to write into, expand. |
+ m_runs.resize(m_runs.size() * 2); |
} |
- if (hr != E_OUTOFMEMORY) { |
- // Some kind of unexpected error. |
- runs_->resize(0); |
- break; |
- } |
- // There was not enough items for it to write into, expand. |
- runs_->resize(runs_->size() * 2); |
- } |
- |
- // Fix up the directions of the items so they're what WebKit thinks |
- // they are. WebKit (and we assume any other caller) always knows what |
- // direction it wants things to be in, and will only give us runs that are in |
- // the same direction. Sometimes, Uniscibe disagrees, for example, if you |
- // have embedded ASCII punctuation in an Arabic string, WebKit will |
- // (correctly) know that is should still be rendered RTL, but Uniscibe might |
- // think LTR is better. |
- // |
- // TODO(brettw) bug 747235: |
- // This workaround fixes the bug but causes spacing problems in other cases. |
- // WebKit sometimes gives us a big run that includes ASCII and Arabic, and |
- // this forcing direction makes those cases incorrect. This seems to happen |
- // during layout only, so it ends up that spacing is incorrect (because being |
- // the wrong direction changes ligatures and stuff). |
- // |
- //for (size_t i = 0; i < runs_->size(); i++) |
- // runs_[i].a.fRTL = is_rtl_; |
} |
+bool UniscribeHelper::Shape(const UChar* input, |
+ int itemLength, |
+ int numGlyphs, |
+ SCRIPT_ITEM& run, |
+ Shaping& shaping) |
+{ |
+ HFONT hfont = m_hfont; |
+ SCRIPT_CACHE* scriptCache = m_scriptCache; |
+ SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; |
+ int ascent = m_ascent; |
+ HDC tempDC = NULL; |
+ HGDIOBJ oldFont = 0; |
+ HRESULT hr; |
+ bool lastFallbackTried = false; |
+ bool result; |
-bool UniscribeState::Shape(const wchar_t* input, |
- int item_length, |
- int num_glyphs, |
- SCRIPT_ITEM& run, |
- Shaping& shaping) { |
- HFONT hfont = hfont_; |
- SCRIPT_CACHE* script_cache = script_cache_; |
- SCRIPT_FONTPROPERTIES* font_properties = font_properties_; |
- int ascent = ascent_; |
- HDC temp_dc = NULL; |
- HGDIOBJ old_font = 0; |
- HRESULT hr; |
- bool lastFallbackTried = false; |
- bool result; |
+ int generatedGlyphs = 0; |
- int generated_glyphs = 0; |
+ // In case HFONT passed in ctor cannot render this run, we have to scan |
+ // other fonts from the beginning of the font list. |
+ ResetFontIndex(); |
- // In case HFONT passed in ctor cannot render this run, we have to scan |
- // other fonts from the beginning of the font list. |
- ResetFontIndex(); |
+ // Compute shapes. |
+ while (true) { |
+ shaping.m_logs.resize(itemLength); |
+ shaping.m_glyphs.resize(numGlyphs); |
+ shaping.m_visattr.resize(numGlyphs); |
- // Compute shapes. |
- while (true) { |
- shaping.logs->resize(item_length); |
- shaping.glyphs->resize(num_glyphs); |
- shaping.visattr->resize(num_glyphs); |
+ // 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_visattr[0], &generatedGlyphs); |
+ if (hr == E_PENDING) { |
+ // Allocate the DC. |
+ tempDC = GetDC(NULL); |
+ oldFont = SelectObject(tempDC, hfont); |
+ continue; |
+ } else if (hr == E_OUTOFMEMORY) { |
+ numGlyphs *= 2; |
+ continue; |
+ } else if (SUCCEEDED(hr) && |
+ (lastFallbackTried || |
+ !ContainsMissingGlyphs(&shaping.m_glyphs[0], |
+ generatedGlyphs, fontProperties))) { |
+ break; |
+ } |
- // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true |
- // here. Is that what we want? It will display control characters. |
- hr = ScriptShape(temp_dc, script_cache, input, item_length, |
- num_glyphs, &run.a, |
- &shaping.glyphs[0], &shaping.logs[0], |
- &shaping.visattr[0], &generated_glyphs); |
- if (hr == E_PENDING) { |
- // Allocate the DC. |
- temp_dc = GetDC(NULL); |
- old_font = SelectObject(temp_dc, hfont); |
- continue; |
- } else if (hr == E_OUTOFMEMORY) { |
- num_glyphs *= 2; |
- continue; |
- } else if (SUCCEEDED(hr) && |
- (lastFallbackTried || !ContainsMissingGlyphs(&shaping.glyphs[0], |
- generated_glyphs, font_properties))) { |
- break; |
- } |
+ // The current font can't render this run. clear DC and try |
+ // next font. |
+ if (tempDC) { |
+ SelectObject(tempDC, oldFont); |
+ ReleaseDC(NULL, tempDC); |
+ tempDC = NULL; |
+ } |
- // The current font can't render this run. clear DC and try |
- // next font. |
- if (temp_dc) { |
- SelectObject(temp_dc, old_font); |
- ReleaseDC(NULL, temp_dc); |
- temp_dc = NULL; |
- } |
+ if (NextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) { |
+ // The primary font does not support this run. Try next font. |
+ // In case of web page rendering, they come from fonts specified in |
+ // CSS stylesheets. |
+ continue; |
+ } else if (!lastFallbackTried) { |
+ lastFallbackTried = true; |
- if (NextWinFontData(&hfont, &script_cache, &font_properties, &ascent)) { |
- // The primary font does not support this run. Try next font. |
- // In case of web page rendering, they come from fonts specified in |
- // CSS stylesheets. |
- continue; |
- } else if (!lastFallbackTried) { |
- lastFallbackTried = true; |
+ // Generate a last fallback font based on the script of |
+ // a character to draw while inheriting size and styles |
+ // from the primary font |
+ if (!m_logfont.lfFaceName[0]) |
+ SetLogFontAndStyle(m_hfont, &m_logfont, &m_style); |
- // Generate a last fallback font based on the script of |
- // a character to draw while inheriting size and styles |
- // from the primary font |
- if (!logfont_.lfFaceName[0]) |
- SetLogFontAndStyle(hfont_, &logfont_, &style_); |
+ // TODO(jungshik): generic type should come from webkit for |
+ // UniscribeHelperTextRun (a derived class used in webkit). |
+ const UChar *family = GetFallbackFamily(input, itemLength, |
+ GENERIC_FAMILY_STANDARD, NULL, NULL); |
+ bool font_ok = GetDerivedFontData(family, m_style, &m_logfont, |
+ &ascent, &hfont, &scriptCache); |
- // TODO(jungshik): generic type should come from webkit for |
- // UniscribeStateTextRun (a derived class used in webkit). |
- const wchar_t *family = GetFallbackFamily(input, item_length, |
- GENERIC_FAMILY_STANDARD, NULL, NULL); |
- bool font_ok = GetDerivedFontData(family, style_, &logfont_, &ascent, &hfont, &script_cache); |
+ if (!font_ok) { |
+ // If this GetDerivedFontData is called from the renderer it |
+ // might fail because the sandbox is preventing it from opening |
+ // the font files. If we are running in the renderer, |
+ // TryToPreloadFont is overridden to ask the browser to preload |
+ // the font for us so we can access it. |
+ TryToPreloadFont(hfont); |
- if (!font_ok) { |
- // If this GetDerivedFontData is called from the renderer it might fail |
- // because the sandbox is preventing it from opening the font files. |
- // If we are running in the renderer, TryToPreloadFont is overridden to |
- // ask the browser to preload the font for us so we can access it. |
- TryToPreloadFont(hfont); |
+ // Try again. |
+ font_ok = GetDerivedFontData(family, m_style, &m_logfont, |
+ &ascent, &hfont, &scriptCache); |
+ ASSERT(font_ok); |
+ } |
- // Try again. |
- font_ok = GetDerivedFontData(family, style_, &logfont_, &ascent, &hfont, &script_cache); |
- DCHECK(font_ok); |
- } |
+ // TODO(jungshik) : Currently GetDerivedHFont always returns a |
+ // a valid HFONT, but in the future, I may change it to return 0. |
+ ASSERT(hfont); |
- // TODO(jungshik) : Currently GetDerivedHFont always returns a |
- // a valid HFONT, but in the future, I may change it to return 0. |
- DCHECK(hfont); |
- |
- // We don't need a font_properties for the last resort fallback font |
- // because we don't have anything more to try and are forced to |
- // accept empty glyph boxes. If we tried a series of fonts as |
- // 'last-resort fallback', we'd need it, but currently, we don't. |
- continue; |
- } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { |
- run.a.eScript = SCRIPT_UNDEFINED; |
- continue; |
- } else if (FAILED(hr)) { |
- // Error shaping. |
- generated_glyphs = 0; |
- result = false; |
- goto cleanup; |
+ // We don't need a font_properties for the last resort fallback font |
+ // because we don't have anything more to try and are forced to |
+ // accept empty glyph boxes. If we tried a series of fonts as |
+ // 'last-resort fallback', we'd need it, but currently, we don't. |
+ continue; |
+ } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { |
+ run.a.eScript = SCRIPT_UNDEFINED; |
+ continue; |
+ } else if (FAILED(hr)) { |
+ // Error shaping. |
+ generatedGlyphs = 0; |
+ result = false; |
+ goto cleanup; |
+ } |
} |
- } |
- // Sets Windows font data for this run to those corresponding to |
- // a font supporting this run. we don't need to store font_properties |
- // because it's not used elsewhere. |
- shaping.hfont_ = hfont; |
- shaping.script_cache_ = script_cache; |
+ // Sets Windows font data for this run to those corresponding to |
+ // a font supporting this run. we don't need to store font_properties |
+ // because it's not used elsewhere. |
+ shaping.m_hfont = hfont; |
+ shaping.m_scriptCache = scriptCache; |
- // The ascent of a font for this run can be different from |
- // that of the primary font so that we need to keep track of |
- // the difference per run and take that into account when calling |
- // ScriptTextOut in |Draw|. Otherwise, different runs rendered by |
- // different fonts would not be aligned vertically. |
- shaping.ascent_offset_ = ascent_ ? ascent - ascent_ : 0; |
- result = true; |
+ // The ascent of a font for this run can be different from |
+ // that of the primary font so that we need to keep track of |
+ // the difference per run and take that into account when calling |
+ // ScriptTextOut in |Draw|. Otherwise, different runs rendered by |
+ // different fonts would not be aligned vertically. |
+ shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0; |
+ result = true; |
-cleanup: |
- shaping.glyphs->resize(generated_glyphs); |
- shaping.visattr->resize(generated_glyphs); |
- shaping.advance->resize(generated_glyphs); |
- shaping.offsets->resize(generated_glyphs); |
- if (temp_dc) { |
- SelectObject(temp_dc, old_font); |
- ReleaseDC(NULL, temp_dc); |
- } |
- // On failure, our logs don't mean anything, so zero those out. |
- if (!result) |
- shaping.logs->clear(); |
+ cleanup: |
+ shaping.m_glyphs.resize(generatedGlyphs); |
+ shaping.m_visattr.resize(generatedGlyphs); |
+ shaping.m_advance.resize(generatedGlyphs); |
+ shaping.m_offsets.resize(generatedGlyphs); |
+ if (tempDC) { |
+ SelectObject(tempDC, oldFont); |
+ ReleaseDC(NULL, tempDC); |
+ } |
+ // On failure, our logs don't mean anything, so zero those out. |
+ if (!result) |
+ shaping.m_logs.clear(); |
- return result; |
+ return result; |
} |
-void UniscribeState::FillShapes() { |
- shapes_->resize(runs_->size()); |
- for (size_t i = 0; i < runs_->size(); i++) { |
- int start_item = runs_[i].iCharPos; |
- int item_length = input_length_ - start_item; |
- if (i < runs_->size() - 1) |
- item_length = runs_[i + 1].iCharPos - start_item; |
+void UniscribeHelper::FillShapes() |
+{ |
+ m_shapes.resize(m_runs.size()); |
+ for (size_t i = 0; i < m_runs.size(); i++) { |
+ int startItem = m_runs[i].iCharPos; |
+ int itemLength = m_inputLength - startItem; |
+ if (i < m_runs.size() - 1) |
+ itemLength = m_runs[i + 1].iCharPos - startItem; |
- int num_glyphs; |
- if (item_length < UNISCRIBE_STATE_STACK_CHARS) { |
- // 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. |
- num_glyphs = UNISCRIBE_STATE_STACK_CHARS; |
- } 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 shrinks, |
- // which is unlikely) and just start with the length recommended by |
- // the Uniscribe documentation as a "usually fits" size. |
- num_glyphs = item_length * 3 / 2 + 16; |
- } |
+ int numGlyphs; |
+ if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) { |
+ // 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; |
+ } 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 |
+ // shrinks, which is unlikely) and just start with the length |
+ // recommended by the Uniscribe documentation as a "usually fits" |
+ // size. |
+ numGlyphs = itemLength * 3 / 2 + 16; |
+ } |
- // 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 = shapes_[i]; |
- if (!Shape(&input_[start_item], item_length, num_glyphs, runs_[i], shaping)) |
- continue; |
+ // 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)) |
+ continue; |
- // Compute placements. Note that offsets is documented incorrectly |
- // and is actually an array. |
+ // Compute placements. Note that offsets is documented incorrectly |
+ // and is actually an array. |
- // DC that we lazily create if Uniscribe commands us to. |
- // (this does not happen often because script_cache is already |
- // updated when calling ScriptShape). |
- HDC temp_dc = NULL; |
- HGDIOBJ old_font = NULL; |
- HRESULT hr; |
- while (true) { |
- shaping.pre_padding = 0; |
- hr = ScriptPlace(temp_dc, shaping.script_cache_, &shaping.glyphs[0], |
- static_cast<int>(shaping.glyphs->size()), |
- &shaping.visattr[0], &runs_[i].a, |
- &shaping.advance[0], &shaping.offsets[0], |
- &shaping.abc); |
- if (hr != E_PENDING) |
- break; |
+ // DC that we lazily create if Uniscribe commands us to. |
+ // (this does not happen often because scriptCache is already |
+ // updated when calling ScriptShape). |
+ HDC tempDC = NULL; |
+ HGDIOBJ oldFont = NULL; |
+ HRESULT hr; |
+ while (true) { |
+ shaping.m_prePadding = 0; |
+ hr = ScriptPlace(tempDC, shaping.m_scriptCache, |
+ &shaping.m_glyphs[0], |
+ static_cast<int>(shaping.m_glyphs.size()), |
+ &shaping.m_visattr[0], &m_runs[i].a, |
+ &shaping.m_advance[0], &shaping.m_offsets[0], |
+ &shaping.m_abc); |
+ if (hr != E_PENDING) |
+ break; |
- // Allocate the DC and run the loop again. |
- temp_dc = GetDC(NULL); |
- old_font = SelectObject(temp_dc, shaping.hfont_); |
- } |
+ // Allocate the DC and run the loop again. |
+ tempDC = GetDC(NULL); |
+ oldFont = SelectObject(tempDC, shaping.m_hfont); |
+ } |
- if (FAILED(hr)) { |
- // Some error we don't know how to handle. Nuke all of our data |
- // since we can't deal with partially valid data later. |
- runs_->clear(); |
- shapes_->clear(); |
- screen_order_->clear(); |
- } |
+ if (FAILED(hr)) { |
+ // 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_shapes.clear(); |
+ m_screenOrder.clear(); |
+ } |
- if (temp_dc) { |
- SelectObject(temp_dc, old_font); |
- ReleaseDC(NULL, temp_dc); |
+ if (tempDC) { |
+ SelectObject(tempDC, oldFont); |
+ ReleaseDC(NULL, tempDC); |
+ } |
} |
- } |
- AdjustSpaceAdvances(); |
+ AdjustSpaceAdvances(); |
- if (letter_spacing_ != 0 || word_spacing_ != 0) |
- ApplySpacing(); |
+ if (m_letterSpacing != 0 || m_wordSpacing != 0) |
+ ApplySpacing(); |
} |
-void UniscribeState::FillScreenOrder() { |
- screen_order_->resize(runs_->size()); |
+void UniscribeHelper::FillScreenOrder() |
+{ |
+ m_screenOrder.resize(m_runs.size()); |
- // We assume that the input has only one text direction in it. |
- // TODO(brettw) are we sure we want to keep this restriction? |
- if (is_rtl_) { |
- for (int i = 0; i < static_cast<int>(screen_order_->size()); i++) |
- screen_order_[static_cast<int>(screen_order_->size()) - i - 1] = i; |
- } else { |
- for (int i = 0; i < static_cast<int>(screen_order_->size()); i++) |
- screen_order_[i] = i; |
- } |
+ // We assume that the input has only one text direction in it. |
+ // TODO(brettw) are we sure we want to keep this restriction? |
+ if (m_isRtl) { |
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) |
+ m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i; |
+ } else { |
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) |
+ m_screenOrder[i] = i; |
+ } |
} |
-void UniscribeState::AdjustSpaceAdvances() { |
- if (space_width_ == 0) |
- return; |
+void UniscribeHelper::AdjustSpaceAdvances() |
+{ |
+ if (m_spaceWidth == 0) |
+ return; |
- int space_width_without_letter_spacing = space_width_ - letter_spacing_; |
+ int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing; |
- // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. |
- for (size_t run = 0; run < runs_->size(); run++) { |
- Shaping& shaping = shapes_[run]; |
+ // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. |
+ for (size_t run = 0; run < m_runs.size(); run++) { |
+ Shaping& shaping = m_shapes[run]; |
- for (int i = 0; i < shaping.char_length(); i++) { |
- if (!TreatAsSpace(input_[runs_[run].iCharPos + i])) |
- continue; |
+ for (int i = 0; i < shaping.charLength(); i++) { |
+ if (!TreatAsSpace(m_input[m_runs[run].iCharPos + i])) |
+ continue; |
- int glyph_index = shaping.logs[i]; |
- int current_advance = shaping.advance[glyph_index]; |
- // Don't give zero-width spaces a width. |
- if (!current_advance) |
- continue; |
+ int glyphIndex = shaping.m_logs[i]; |
+ int currentAdvance = shaping.m_advance[glyphIndex]; |
+ // Don't give zero-width spaces a width. |
+ if (!currentAdvance) |
+ continue; |
- // current_advance does not include additional letter-spacing, but |
- // space_width does. Here we find out how off we are from the correct |
- // width for the space not including letter-spacing, then just subtract |
- // that diff. |
- int diff = current_advance - space_width_without_letter_spacing; |
- // The shaping can consist of a run of text, so only subtract the |
- // difference in the width of the glyph. |
- shaping.advance[glyph_index] -= diff; |
- shaping.abc.abcB -= diff; |
+ // currentAdvance does not include additional letter-spacing, but |
+ // space_width does. Here we find out how off we are from the |
+ // correct width for the space not including letter-spacing, then |
+ // just subtract that diff. |
+ int diff = currentAdvance - spaceWidthWithoutLetterSpacing; |
+ // The shaping can consist of a run of text, so only subtract the |
+ // difference in the width of the glyph. |
+ shaping.m_advance[glyphIndex] -= diff; |
+ shaping.m_abc.abcB -= diff; |
+ } |
} |
- } |
} |
-void UniscribeState::ApplySpacing() { |
- for (size_t run = 0; run < runs_->size(); run++) { |
- Shaping& shaping = shapes_[run]; |
- bool is_rtl = runs_[run].a.fRTL; |
+void UniscribeHelper::ApplySpacing() |
+{ |
+ for (size_t run = 0; run < m_runs.size(); run++) { |
+ Shaping& shaping = m_shapes[run]; |
+ bool isRtl = m_runs[run].a.fRTL; |
- if (letter_spacing_ != 0) { |
- // RTL text gets padded to the left of each character. We increment the |
- // run's advance to make this happen. This will be balanced out by NOT |
- // adding additional advance to the last glyph in the run. |
- if (is_rtl) |
- shaping.pre_padding += letter_spacing_; |
+ if (m_letterSpacing != 0) { |
+ // RTL text gets padded to the left of each character. We increment |
+ // the run's advance to make this happen. This will be balanced out |
+ // by NOT adding additional advance to the last glyph in the run. |
+ if (isRtl) |
+ shaping.m_prePadding += m_letterSpacing; |
- // Go through all the glyphs in this run and increase the "advance" to |
- // account for letter spacing. We adjust letter spacing only on cluster |
- // boundaries. |
- // |
- // This works for most scripts, but may have problems with some indic |
- // scripts. This behavior is better than Firefox or IE for Hebrew. |
- for (int i = 0; i < shaping.glyph_length(); i++) { |
- if (shaping.visattr[i].fClusterStart) { |
- // Ick, we need to assign the extra space so that the glyph comes |
- // first, then is followed by the space. This is opposite for RTL. |
- if (is_rtl) { |
- if (i != shaping.glyph_length() - 1) { |
- // All but the last character just get the spacing applied to |
- // their advance. The last character doesn't get anything, |
- shaping.advance[i] += letter_spacing_; |
- shaping.abc.abcB += letter_spacing_; |
+ // Go through all the glyphs in this run and increase the "advance" |
+ // to account for letter spacing. We adjust letter spacing only on |
+ // cluster boundaries. |
+ // |
+ // This works for most scripts, but may have problems with some |
+ // indic scripts. This behavior is better than Firefox or IE for |
+ // Hebrew. |
+ for (int i = 0; i < shaping.glyphLength(); i++) { |
+ if (shaping.m_visattr[i].fClusterStart) { |
+ // Ick, we need to assign the extra space so that the glyph |
+ // comes first, then is followed by the space. This is |
+ // opposite for RTL. |
+ if (isRtl) { |
+ if (i != shaping.glyphLength() - 1) { |
+ // All but the last character just get the spacing |
+ // applied to their advance. The last character |
+ // doesn't get anything, |
+ shaping.m_advance[i] += m_letterSpacing; |
+ shaping.m_abc.abcB += m_letterSpacing; |
+ } |
+ } else { |
+ // LTR case is easier, we just add to the advance. |
+ shaping.m_advance[i] += m_letterSpacing; |
+ shaping.m_abc.abcB += m_letterSpacing; |
+ } |
+ } |
} |
- } else { |
- // LTR case is easier, we just add to the advance. |
- shaping.advance[i] += letter_spacing_; |
- shaping.abc.abcB += letter_spacing_; |
- } |
} |
- } |
- } |
- // Go through all the characters to find whitespace and insert the extra |
- // wordspacing amount for the glyphs they correspond to. |
- if (word_spacing_ != 0) { |
- for (int i = 0; i < shaping.char_length(); i++) { |
- if (!TreatAsSpace(input_[runs_[run].iCharPos + i])) |
- continue; |
+ // Go through all the characters to find whitespace and insert the |
+ // extra wordspacing amount for the glyphs they correspond to. |
+ if (m_wordSpacing != 0) { |
+ for (int i = 0; i < shaping.charLength(); i++) { |
+ if (!TreatAsSpace(m_input[m_runs[run].iCharPos + i])) |
+ continue; |
- // The char in question is a word separator... |
- int glyph_index = shaping.logs[i]; |
+ // The char in question is a word separator... |
+ int glyphIndex = shaping.m_logs[i]; |
- // Spaces will not have a glyph in Uniscribe, it will just add |
- // additional advance to the character to the left of the space. The |
- // space's corresponding glyph will be the character following it in |
- // reading order. |
- if (is_rtl) { |
- // In RTL, the glyph to the left of the space is the same as the |
- // first glyph of the following character, so we can just increment |
- // it. |
- shaping.advance[glyph_index] += word_spacing_; |
- shaping.abc.abcB += word_spacing_; |
- } else { |
- // LTR is actually more complex here, we apply it to the previous |
- // character if there is one, otherwise we have to apply it to the |
- // leading space of the run. |
- if (glyph_index == 0) { |
- shaping.pre_padding += word_spacing_; |
- } else { |
- shaping.advance[glyph_index - 1] += word_spacing_; |
- shaping.abc.abcB += word_spacing_; |
- } |
- } |
- } |
- } // word_spacing_ != 0 |
+ // Spaces will not have a glyph in Uniscribe, it will just add |
+ // additional advance to the character to the left of the |
+ // space. The space's corresponding glyph will be the character |
+ // following it in reading order. |
+ if (isRtl) { |
+ // In RTL, the glyph to the left of the space is the same |
+ // as the first glyph of the following character, so we can |
+ // just increment it. |
+ shaping.m_advance[glyphIndex] += m_wordSpacing; |
+ shaping.m_abc.abcB += m_wordSpacing; |
+ } else { |
+ // LTR is actually more complex here, we apply it to the |
+ // previous character if there is one, otherwise we have to |
+ // apply it to the leading space of the run. |
+ if (glyphIndex == 0) { |
+ shaping.m_prePadding += m_wordSpacing; |
+ } else { |
+ shaping.m_advance[glyphIndex - 1] += m_wordSpacing; |
+ shaping.m_abc.abcB += m_wordSpacing; |
+ } |
+ } |
+ } |
+ } // m_wordSpacing != 0 |
- // Loop for next run... |
- } |
+ // Loop for next run... |
+ } |
} |
// The advance is the ABC width of the run |
-int UniscribeState::AdvanceForItem(int item_index) const { |
- int accum = 0; |
- const Shaping& shaping = shapes_[item_index]; |
+int UniscribeHelper::AdvanceForItem(int item_index) const |
+{ |
+ int accum = 0; |
+ const Shaping& shaping = m_shapes[item_index]; |
- if (shaping.justify->empty()) { |
- // Easy case with no justification, the width is just the ABC width of t |
- // the run. (The ABC width is the sum of the advances). |
- return shaping.abc.abcA + shaping.abc.abcB + shaping.abc.abcC + |
- shaping.pre_padding; |
- } |
+ if (shaping.m_justify.size() == 0) { |
+ // Easy case with no justification, the width is just the ABC width of |
+ // the run. (The ABC width is the sum of the advances). |
+ return shaping.m_abc.abcA + shaping.m_abc.abcB + |
+ shaping.m_abc.abcC + shaping.m_prePadding; |
+ } |
- // With justification, we use the justified amounts instead. The |
- // justification array contains both the advance and the extra space |
- // added for justification, so is the width we want. |
- int justification = 0; |
- for (size_t i = 0; i < shaping.justify->size(); i++) |
- justification += shaping.justify[i]; |
+ // With justification, we use the justified amounts instead. The |
+ // justification array contains both the advance and the extra space |
+ // added for justification, so is the width we want. |
+ int justification = 0; |
+ for (size_t i = 0; i < shaping.m_justify.size(); i++) |
+ justification += shaping.m_justify[i]; |
- return shaping.pre_padding + justification; |
+ return shaping.m_prePadding + justification; |
} |
-} // namespace gfx |
- |
+} // namespace WebCore |
Property changes on: webkit\port\platform\graphics\UniscribeHelper.cpp |
___________________________________________________________________ |
Added: svn:mergeinfo |
Merged /branches/chrome_webkit_merge_branch/base/gfx/uniscribe.cc:r69-2775 |