summaryrefslogtreecommitdiffstats
path: root/webkit/port/platform/graphics/UniscribeHelper.h
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/port/platform/graphics/UniscribeHelper.h')
-rw-r--r--webkit/port/platform/graphics/UniscribeHelper.h380
1 files changed, 380 insertions, 0 deletions
diff --git a/webkit/port/platform/graphics/UniscribeHelper.h b/webkit/port/platform/graphics/UniscribeHelper.h
new file mode 100644
index 0000000..27d7961
--- /dev/null
+++ b/webkit/port/platform/graphics/UniscribeHelper.h
@@ -0,0 +1,380 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A wrapper around Uniscribe that provides a reasonable API.
+
+#ifndef UniscribeHelper_h
+#define UniscribeHelper_h
+
+#include <windows.h>
+#include <usp10.h>
+#include <map>
+
+#include "wtf/Vector.h"
+
+#include "testing/gtest/include/gtest/gtest_prod.h"
+#include "unicode/uchar.h"
+
+namespace WebCore {
+
+#define UNISCRIBE_HELPER_STACK_RUNS 8
+#define UNISCRIBE_HELPER_STACK_CHARS 32
+
+// 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
+// compute).
+//
+// This object is "kind of large" (~1K) because it reserves a lot of space for
+// working with to avoid expensive heap operations. Therefore, not only should
+// you not worry about creating and destroying it, you should try to not keep
+// them around.
+class UniscribeHelper {
+public:
+ // Initializes this Uniscribe run with the text pointed to by |run| with
+ // |length|. The input is NOT null terminated.
+ //
+ // The is_rtl flag should be set if the input script is RTL. It is assumed
+ // that the caller has already divided up the input text (using ICU, for
+ // example) into runs of the same direction of script. This avoids
+ // disagreements between the caller and Uniscribe later (see FillItems).
+ //
+ // A script cache should be provided by the caller that is initialized to
+ // NULL. When the caller is done with the cache (it may be stored between
+ // runs as long as it is used consistently with the same HFONT), it should
+ // call ScriptFreeCache().
+ UniscribeHelper(const UChar* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE* scriptCache,
+ SCRIPT_FONTPROPERTIES* fontProperties);
+
+ virtual ~UniscribeHelper();
+
+ // Sets Uniscribe's directional override flag. False by default.
+ bool directionalOverride() const
+ {
+ return m_directionalOverride;
+ }
+ void setDirectionalOverride(bool override)
+ {
+ m_directionalOverride = override;
+ }
+
+ // Set's Uniscribe's no-ligate override flag. False by default.
+ bool inhibitLigate() const
+ {
+ return m_inhibitLigate;
+ }
+ void setInhibitLigate(bool inhibit)
+ {
+ m_inhibitLigate = inhibit;
+ }
+
+ // Set letter spacing. We will try to insert this much space between
+ // graphemes (one or more glyphs perceived as a single unit by ordinary
+ // users of a script). Positive values increase letter spacing, negative
+ // values decrease it. 0 by default.
+ int letterSpacing() const
+ {
+ return m_letterSpacing;
+ }
+ void setLetterSpacing(int letterSpacing)
+ {
+ m_letterSpacing = letterSpacing;
+ }
+
+ // Set the width of a standard space character. We use this to normalize
+ // space widths. Windows will make spaces after Hindi characters larger than
+ // other spaces. A space_width of 0 means to use the default space width.
+ //
+ // Must be set before Init() is called.
+ int spaceWidth() const
+ {
+ return m_spaceWidth;
+ }
+ void setSpaceWidth(int spaceWidth)
+ {
+ m_spaceWidth = spaceWidth;
+ }
+
+ // Set word spacing. We will try to insert this much extra space between
+ // each word in the input (beyond whatever whitespace character separates
+ // words). Positive values lead to increased letter spacing, negative values
+ // decrease it. 0 by default.
+ //
+ // Must be set before Init() is called.
+ int wordSpacing() const
+ {
+ return m_wordSpacing;
+ }
+ void setWordSpacing(int wordSpacing)
+ {
+ m_wordSpacing = wordSpacing;
+ }
+
+ void setAscent(int ascent)
+ {
+ m_ascent = ascent;
+ }
+
+ // You must call this after setting any options but before doing any
+ // other calls like asking for widths or drawing.
+ void Init()
+ {
+ InitWithOptionalLengthProtection(true);
+ }
+
+ // Returns the total width in pixels of the text run.
+ int Width() const;
+
+ // Call to justify the text, with the amount of space that should be ADDED
+ // to get the desired width that the column should be justified to.
+ // Normally, spaces are inserted, but for Arabic there will be kashidas
+ // (extra strokes) inserted instead.
+ //
+ // This function MUST be called AFTER Init().
+ void Justify(int additionalSpace);
+
+ // Computes the given character offset into a pixel offset of the beginning
+ // of that character.
+ int CharacterToX(int offset) const;
+
+ // Converts the given pixel X position into a logical character offset into
+ // the run. For positions appearing before the first character, this will
+ // return -1.
+ int XToCharacter(int x) const;
+
+ // Draws the given characters to (x, y) in the given DC. The font will be
+ // handled by this function, but the font color and other attributes should
+ // be pre-set.
+ //
+ // The y position is the upper left corner, NOT the baseline.
+ void Draw(HDC dc, int x, int y, int from, int to);
+
+ // Returns the first glyph assigned to the character at the given offset.
+ // This function is used to retrieve glyph information when Uniscribe is
+ // being used to generate glyphs for non-complex, non-BMP (above U+FFFF)
+ // characters. These characters are not otherwise special and have no
+ // complex shaping rules, so we don't otherwise need Uniscribe, except
+ // Uniscribe is the only way to get glyphs for non-BMP characters.
+ //
+ // Returns 0 if there is no glyph for the given character.
+ WORD FirstGlyphForCharacter(int charOffset) const;
+
+protected:
+ // Backend for init. The flag allows the unit test to specify whether we
+ // should fail early for very long strings like normal, or try to pass the
+ // long string to Uniscribe. The latter provides a way to force failure of
+ // shaping.
+ void InitWithOptionalLengthProtection(bool lengthProtection);
+
+ // Tries to preload the font when the it is not accessible.
+ // This is the default implementation and it does not do anything.
+ virtual void TryToPreloadFont(HFONT font) {}
+
+private:
+ FRIEND_TEST(UniscribeTest, TooBig);
+
+ // An array corresponding to each item in runs_ containing information
+ // on each of the glyphs that were generated. Like runs_, this is in
+ // reading order. However, for rtl text, the characters within each
+ // item will be reversed.
+ struct Shaping {
+ Shaping()
+ : m_prePadding(0)
+ , m_hfont(NULL)
+ , m_scriptCache(NULL)
+ , m_ascentOffset(0) {
+ m_abc.abcA = 0;
+ m_abc.abcB = 0;
+ m_abc.abcC = 0;
+ }
+
+ // Returns the number of glyphs (which will be drawn to the screen)
+ // in this run.
+ int glyphLength() const
+ {
+ return static_cast<int>(m_glyphs.size());
+ }
+
+ // Returns the number of characters (that we started with) in this run.
+ int charLength() const
+ {
+ return static_cast<int>(m_logs.size());
+ }
+
+ // Returns the advance array that should be used when measuring glyphs.
+ // The returned pointer will indicate an array with glyph_length()
+ // elements and the advance that should be used for each one. This is
+ // either the real advance, or the justified advances if there is one,
+ // and is the array we want to use for measurement.
+ const int* effectiveAdvances() const
+ {
+ if (m_advance.size() == 0)
+ return 0;
+ if (m_justify.size() == 0)
+ return &m_advance[0];
+ return &m_justify[0];
+ }
+
+ // This is the advance amount of space that we have added to the
+ // beginning of the run. It is like the ABC's |A| advance but one that
+ // we create and must handle internally whenever computing with pixel
+ // offsets.
+ int m_prePadding;
+
+ // Glyph indices in the font used to display this item. These indices
+ // are in screen order.
+ Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> 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.
+ //
+ // All offsets are from the beginning of this run. Multiple characters
+ // 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;
+
+ // Flags and such for each glyph.
+ Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visattr;
+
+ // Horizontal advances for each glyph listed above, this is basically
+ // how wide each glyph is.
+ Vector<int, UNISCRIBE_HELPER_STACK_CHARS> 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;
+
+ // Filled by a call to Justify, this is empty for nonjustified text.
+ // If nonempty, this contains the array of justify characters for each
+ // character as returned by ScriptJustify.
+ //
+ // 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;
+
+ // Sizing information for this run. This treats the entire run as a
+ // character with a preceeding advance, width, and ending advance. The
+ // B width is the sum of the |advance| array, and the A and C widths
+ // are any extra spacing applied to each end.
+ //
+ // It is unclear from the documentation what this actually means. From
+ // experimentation, it seems that the sum of the character advances is
+ // always the sum of the ABC values, and I'm not sure what you're
+ // supposed to do with the ABC values.
+ ABC m_abc;
+
+ // Pointers to windows font data used to render this run.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+
+ // Ascent offset between the ascent of the primary font
+ // and that of the fallback font. The offset needs to be applied,
+ // when drawing a string, to align multiple runs rendered with
+ // different fonts.
+ int m_ascentOffset;
+ };
+
+ // Computes the runs_ array from the text run.
+ void FillRuns();
+
+ // Computes the shapes_ array given an runs_ array already filled in.
+ void FillShapes();
+
+ // Fills in the screen_order_ array (see below).
+ void FillScreenOrder();
+
+ // Called to update the glyph positions based on the current spacing
+ // options that are set.
+ void ApplySpacing();
+
+ // Normalizes all advances for spaces to the same width. This keeps windows
+ // from making spaces after Hindi characters larger, which is then
+ // inconsistent with our meaure of the width since WebKit doesn't include
+ // spaces in text-runs sent to uniscribe unless white-space:pre.
+ void AdjustSpaceAdvances();
+
+ // Returns the total width of a single item.
+ int AdvanceForItem(int item_index) const;
+
+ // Shapes a run (pointed to by |input|) using |hfont| first.
+ // Tries a series of fonts specified retrieved with NextWinFontData
+ // and finally a font covering characters in |*input|. A string pointed
+ // 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 item_length,
+ int num_glyphs,
+ SCRIPT_ITEM& run,
+ Shaping& 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
+ // without touching any of out params. Need to call ResetFontIndex
+ // to start scanning of the font list from the beginning.
+ virtual bool NextWinFontData(HFONT* hfont,
+ SCRIPT_CACHE** script_cache,
+ SCRIPT_FONTPROPERTIES** font_properties,
+ int* ascent) {
+ return false;
+ }
+
+ // Resets the font index to the first in the list of fonts to try after the
+ // primaryFont turns out not to work. With fontIndex reset,
+ // NextWinFontData scans fallback fonts from the beginning.
+ virtual void ResetFontIndex() {}
+
+ // The input data for this run of Uniscribe. See the constructor.
+ const UChar* m_input;
+ const int m_inputLength;
+ const bool m_isRtl;
+
+ // Windows font data for the primary font. In a sense, m_logfont and m_style
+ // are redundant because m_hfont contains all the information. However,
+ // invoking GetObject, everytime we need the height and the style, is rather
+ // expensive so that we cache them. Would it be better to add getter and
+ // (virtual) setter for the height and the style of the primary font,
+ // instead of m_logfont? Then, a derived class ctor can set m_ascent,
+ // m_height and m_style if they're known. Getters for them would have to
+ // 'infer' their values from m_hfont ONLY when they're not set.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+ SCRIPT_FONTPROPERTIES* m_fontProperties;
+ int m_ascent;
+ LOGFONT m_logfont;
+ int m_style;
+
+ // Options, see the getters/setters above.
+ bool m_directionalOverride;
+ bool m_inhibitLigate;
+ int m_letterSpacing;
+ int m_spaceWidth;
+ int m_wordSpacing;
+
+ // 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<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes;
+
+ // 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,
+ // or mixed (although WebKit's |TextRun| should really be only one
+ // direction), this makes it very difficult to compute character offsets
+ // 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;
+};
+
+} // namespace WebCore
+
+#endif // UniscribeHelper_h