summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-09 22:51:24 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-09 22:51:24 +0000
commite2051fde97eab43065d52214fe9e9e6fc86c761e (patch)
tree515f2c84cfcba63f5990f6c65c1986aff089fe0a
parent4b4a737b48a8ab184bc99be6a25675f565a4acbd (diff)
downloadchromium_src-e2051fde97eab43065d52214fe9e9e6fc86c761e.zip
chromium_src-e2051fde97eab43065d52214fe9e9e6fc86c761e.tar.gz
chromium_src-e2051fde97eab43065d52214fe9e9e6fc86c761e.tar.bz2
Merge 144623 - Implement right-to-left text rendering in Pepper.
TEST=included BUG=http://crbug.com/134394 Review URL: https://chromiumcodereview.appspot.com/10658037 TBR=brettw@chromium.org git-svn-id: svn://svn.chromium.org/chrome/branches/1180/src@145768 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ppapi/api/dev/ppb_font_dev.idl18
-rw-r--r--ppapi/api/trusted/ppb_browser_font_trusted.idl4
-rw-r--r--ppapi/c/dev/ppb_font_dev.h20
-rw-r--r--ppapi/c/trusted/ppb_browser_font_trusted.h6
-rw-r--r--ppapi/shared_impl/private/ppb_browser_font_trusted_shared.cc145
-rw-r--r--ppapi/tests/test_browser_font.cc90
-rw-r--r--ppapi/tests/test_browser_font.h2
7 files changed, 259 insertions, 26 deletions
diff --git a/ppapi/api/dev/ppb_font_dev.idl b/ppapi/api/dev/ppb_font_dev.idl
index f951d8d..5d582d1 100644
--- a/ppapi/api/dev/ppb_font_dev.idl
+++ b/ppapi/api/dev/ppb_font_dev.idl
@@ -122,12 +122,28 @@ struct PP_TextRun_Dev {
/**
* Set to PP_TRUE if the text is right-to-left.
+ *
+ * When <code>override_direction</code> is false, the browser will perform
+ * the Unicode Bidirectional Algorithm (http://unicode.org/reports/tr9/) on
+ * the text. The value of the <code>rtl</code> flag specifies the
+ * direcionality of the surrounding environment. This means that Hebrew
+ * word will always display right to left, even if <code>rtl</code> is false.
+ *
+ * When <code>override_direction</code> is true, no autodetection will be done
+ * and <code>rtl</code> specifies the direction of the text.
+ *
+ * TODO(brettw) note that autodetection with rtl = true is currently
+ * unimplemented.
*/
PP_Bool rtl;
/**
* Set to PP_TRUE to force the directionality of the text regardless of
- * content
+ * content.
+ *
+ * If this flag is set, the browser will skip autodetection of the content
+ * and will display all text in the direction speficied by the
+ * <code>rtl</code> flag.
*/
PP_Bool override_direction;
};
diff --git a/ppapi/api/trusted/ppb_browser_font_trusted.idl b/ppapi/api/trusted/ppb_browser_font_trusted.idl
index 7c0c633..79cee8c 100644
--- a/ppapi/api/trusted/ppb_browser_font_trusted.idl
+++ b/ppapi/api/trusted/ppb_browser_font_trusted.idl
@@ -237,6 +237,10 @@ interface PPB_BrowserFont_Trusted {
* the string. This handles complex scripts such as Arabic, where characters
* may be combined or replaced depending on the context. Returns (uint32)-1
* on failure.
+ *
+ * TODO(brettw) this function may be broken. See the CharPosRTL test. It
+ * seems to tell you "insertion point" rather than painting position. This
+ * is useful but maybe not what we intended here.
*/
uint32_t CharacterOffsetForPixel(
[in] PP_Resource font,
diff --git a/ppapi/c/dev/ppb_font_dev.h b/ppapi/c/dev/ppb_font_dev.h
index 6ba36a6..ad85a24 100644
--- a/ppapi/c/dev/ppb_font_dev.h
+++ b/ppapi/c/dev/ppb_font_dev.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* From dev/ppb_font_dev.idl modified Tue Oct 11 10:01:39 2011. */
+/* From dev/ppb_font_dev.idl modified Mon Jun 25 14:54:48 2012. */
#ifndef PPAPI_C_DEV_PPB_FONT_DEV_H_
#define PPAPI_C_DEV_PPB_FONT_DEV_H_
@@ -141,11 +141,27 @@ struct PP_TextRun_Dev {
struct PP_Var text;
/**
* Set to PP_TRUE if the text is right-to-left.
+ *
+ * When <code>override_direction</code> is false, the browser will perform
+ * the Unicode Bidirectional Algorithm (http://unicode.org/reports/tr9/) on
+ * the text. The value of the <code>rtl</code> flag specifies the
+ * direcionality of the surrounding environment. This means that Hebrew
+ * word will always display right to left, even if <code>rtl</code> is false.
+ *
+ * When <code>override_direction</code> is true, no autodetection will be done
+ * and <code>rtl</code> specifies the direction of the text.
+ *
+ * TODO(brettw) note that autodetection with rtl = true is currently
+ * unimplemented.
*/
PP_Bool rtl;
/**
* Set to PP_TRUE to force the directionality of the text regardless of
- * content
+ * content.
+ *
+ * If this flag is set, the browser will skip autodetection of the content
+ * and will display all text in the direction speficied by the
+ * <code>rtl</code> flag.
*/
PP_Bool override_direction;
};
diff --git a/ppapi/c/trusted/ppb_browser_font_trusted.h b/ppapi/c/trusted/ppb_browser_font_trusted.h
index 080d024..c16a153 100644
--- a/ppapi/c/trusted/ppb_browser_font_trusted.h
+++ b/ppapi/c/trusted/ppb_browser_font_trusted.h
@@ -4,7 +4,7 @@
*/
/* From trusted/ppb_browser_font_trusted.idl,
- * modified Tue Feb 14 08:45:20 2012.
+ * modified Wed Jun 27 14:43:20 2012.
*/
#ifndef PPAPI_C_TRUSTED_PPB_BROWSER_FONT_TRUSTED_H_
@@ -252,6 +252,10 @@ struct PPB_BrowserFont_Trusted_1_0 {
* the string. This handles complex scripts such as Arabic, where characters
* may be combined or replaced depending on the context. Returns (uint32)-1
* on failure.
+ *
+ * TODO(brettw) this function may be broken. See the CharPosRTL test. It
+ * seems to tell you "insertion point" rather than painting position. This
+ * is useful but maybe not what we intended here.
*/
uint32_t (*CharacterOffsetForPixel)(
PP_Resource font,
diff --git a/ppapi/shared_impl/private/ppb_browser_font_trusted_shared.cc b/ppapi/shared_impl/private/ppb_browser_font_trusted_shared.cc
index e5414b3..9b2c0f5 100644
--- a/ppapi/shared_impl/private/ppb_browser_font_trusted_shared.cc
+++ b/ppapi/shared_impl/private/ppb_browser_font_trusted_shared.cc
@@ -21,6 +21,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFont.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFontDescription.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextRun.h"
+#include "unicode/ubidi.h"
using ppapi::StringVar;
using ppapi::thunk::EnterResourceNoLock;
@@ -51,6 +52,74 @@ string16 GetFontFromMap(
return string16();
}
+// Splits a PP_BrowserFont_Trusted_TextRun into a sequence or LTR and RTL
+// WebTextRuns that can be used for WebKit. Normally WebKit does this for us,
+// but the font drawing and measurement routines we call happen after this
+// step. So for correct rendering of RTL content, we need to do it ourselves.
+class TextRunCollection {
+ public:
+ explicit TextRunCollection(const PP_BrowserFont_Trusted_TextRun& run)
+ : bidi_(NULL),
+ num_runs_(0) {
+ StringVar* text_string = StringVar::FromPPVar(run.text);
+ if (!text_string)
+ return; // Leave num_runs_ = 0 so we'll do nothing.
+ text_ = UTF8ToUTF16(text_string->value());
+
+ if (run.override_direction) {
+ // Skip autodetection.
+ num_runs_ = 1;
+ override_run_ = WebTextRun(text_, PP_ToBool(run.rtl), true);
+ } else {
+ bidi_ = ubidi_open();
+ UErrorCode uerror = U_ZERO_ERROR;
+ ubidi_setPara(bidi_, text_.data(), text_.size(), run.rtl, NULL, &uerror);
+ if (U_SUCCESS(uerror))
+ num_runs_ = ubidi_countRuns(bidi_, &uerror);
+ }
+ }
+
+ ~TextRunCollection() {
+ if (bidi_)
+ ubidi_close(bidi_);
+ }
+
+ const string16& text() const { return text_; }
+ int num_runs() const { return num_runs_; }
+
+ // Returns a WebTextRun with the info for the run at the given index.
+ // The range covered by the run is in the two output params.
+ WebTextRun GetRunAt(int index, int32_t* run_start, int32_t* run_len) const {
+ DCHECK(index < num_runs_);
+ if (bidi_) {
+ bool run_rtl = !!ubidi_getVisualRun(bidi_, index, run_start, run_len);
+ return WebTextRun(string16(&text_[*run_start], *run_len),
+ run_rtl, true);
+ }
+
+ // Override run, return the single one.
+ DCHECK(index == 0);
+ *run_start = 0;
+ *run_len = static_cast<int32_t>(text_.size());
+ return override_run_;
+ }
+
+ private:
+ // Will be null if we skipped autodetection.
+ UBiDi* bidi_;
+
+ // Text of all the runs.
+ string16 text_;
+
+ int num_runs_;
+
+ // When the content specifies override_direction (bidi_ is null) then this
+ // will contain the single text run for WebKit.
+ WebTextRun override_run_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextRunCollection);
+};
+
bool PPTextRunToWebTextRun(const PP_BrowserFont_Trusted_TextRun& text,
WebTextRun* run) {
StringVar* text_string = StringVar::FromPPVar(text.text);
@@ -280,25 +349,53 @@ int32_t PPB_BrowserFont_Trusted_Shared::MeasureText(
uint32_t PPB_BrowserFont_Trusted_Shared::CharacterOffsetForPixel(
const PP_BrowserFont_Trusted_TextRun* text,
int32_t pixel_position) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(*text, &run))
- return -1;
- return static_cast<uint32_t>(font_->offsetForPosition(
- run, static_cast<float>(pixel_position)));
+ TextRunCollection runs(*text);
+ int32_t cur_pixel_offset = 0;
+ for (int i = 0; i < runs.num_runs(); i++) {
+ int32_t run_begin = 0;
+ int32_t run_len = 0;
+ WebTextRun run = runs.GetRunAt(i, &run_begin, &run_len);
+ int run_width = font_->calculateWidth(run);
+ if (pixel_position < cur_pixel_offset + run_width) {
+ // Offset is in this run.
+ return static_cast<uint32_t>(font_->offsetForPosition(
+ run, static_cast<float>(pixel_position - cur_pixel_offset))) +
+ run_begin;
+ }
+ cur_pixel_offset += run_width;
+ }
+ return runs.text().size();
}
int32_t PPB_BrowserFont_Trusted_Shared::PixelOffsetForCharacter(
const PP_BrowserFont_Trusted_TextRun* text,
uint32_t char_offset) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(*text, &run))
- return -1;
- if (char_offset >= run.text.length())
- return -1;
-
- WebFloatRect rect = font_->selectionRectForText(
- run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset);
- return static_cast<int>(rect.width);
+ TextRunCollection runs(*text);
+ int32_t cur_pixel_offset = 0;
+ for (int i = 0; i < runs.num_runs(); i++) {
+ int32_t run_begin = 0;
+ int32_t run_len = 0;
+ WebTextRun run = runs.GetRunAt(i, &run_begin, &run_len);
+ if (char_offset >= static_cast<uint32_t>(run_begin) &&
+ char_offset < static_cast<uint32_t>(run_begin + run_len)) {
+ // Character we're looking for is in this run.
+ //
+ // Here we ask WebKit to give us the rectangle around the character in
+ // question, and then return the left edge. If we asked for a range of
+ // 0 characters starting at the character in question, it would give us
+ // a 0-width rect around the insertion point. But that will be on the
+ // right side of the character for an RTL run, which would be wrong.
+ WebFloatRect rect = font_->selectionRectForText(
+ run, WebFloatPoint(0.0f, 0.0f), font_->height(),
+ char_offset - run_begin, char_offset - run_begin + 1);
+ return cur_pixel_offset + static_cast<int>(rect.x);
+ } else {
+ // Character is past this run, account for the pixels and continue
+ // looking.
+ cur_pixel_offset += font_->calculateWidth(run);
+ }
+ }
+ return -1; // Requested a char beyond the end.
}
void PPB_BrowserFont_Trusted_Shared::DrawTextToCanvas(
@@ -308,10 +405,6 @@ void PPB_BrowserFont_Trusted_Shared::DrawTextToCanvas(
uint32_t color,
const PP_Rect* clip,
PP_Bool image_data_is_opaque) {
- WebTextRun run;
- if (!PPTextRunToWebTextRun(text, &run))
- return;
-
// Convert position and clip.
WebFloatPoint web_position(static_cast<float>(position->x),
static_cast<float>(position->y));
@@ -328,8 +421,20 @@ void PPB_BrowserFont_Trusted_Shared::DrawTextToCanvas(
clip->size.width, clip->size.height);
}
- font_->drawText(destination, run, web_position, color, web_clip,
- PP_ToBool(image_data_is_opaque));
+ TextRunCollection runs(text);
+ for (int i = 0; i < runs.num_runs(); i++) {
+ int32_t run_begin = 0;
+ int32_t run_len = 0;
+ WebTextRun run = runs.GetRunAt(i, &run_begin, &run_len);
+ font_->drawText(destination, run, web_position, color, web_clip,
+ PP_ToBool(image_data_is_opaque));
+
+ // Advance to the next run. Note that we avoid doing this for the last run
+ // since it's unnecessary, measuring text is slow, and most of the time
+ // there will be only one run anyway.
+ if (i != runs.num_runs() - 1)
+ web_position.x += font_->calculateWidth(run);
+ }
}
} // namespace ppapi
diff --git a/ppapi/tests/test_browser_font.cc b/ppapi/tests/test_browser_font.cc
index 9f3a2e0..8fc4104 100644
--- a/ppapi/tests/test_browser_font.cc
+++ b/ppapi/tests/test_browser_font.cc
@@ -4,8 +4,6 @@
#include "ppapi/tests/test_browser_font.h"
-#include <stdio.h>// ERASEME
-
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"
#include "ppapi/cpp/image_data.h"
@@ -20,7 +18,11 @@ bool TestBrowserFont::Init() {
void TestBrowserFont::RunTests(const std::string& filter) {
RUN_TEST(FontFamilies, filter);
RUN_TEST(Measure, filter);
+ RUN_TEST(MeasureRTL, filter);
RUN_TEST(CharPos, filter);
+ // This test is disabled. It doesn't currently pass. See the
+ // CharacterOffsetForPixel API.
+ //RUN_TEST(CharPosRTL, filter);
RUN_TEST(Draw, filter);
}
@@ -54,6 +56,48 @@ std::string TestBrowserFont::TestMeasure() {
PASS();
}
+std::string TestBrowserFont::TestMeasureRTL() {
+ pp::BrowserFontDescription desc;
+ pp::BrowserFont_Trusted font(instance_, desc);
+
+ // Mixed string, two chars of LTR, two of RTL, then two of LTR.
+ // Note this is in UTF-8 so has more than 6 bytes.
+ std::string mixed("AB\xd7\x94\xd7\x97ZZ");
+ const int kNumChars = 6;
+ pp::BrowserFontTextRun run(mixed);
+
+ // Note that since this is UTF-8, the two RTL chars are two bytes each.
+ int32_t len[kNumChars];
+ len[0] = font.PixelOffsetForCharacter(run, 0);
+ len[1] = font.PixelOffsetForCharacter(run, 1);
+ len[2] = font.PixelOffsetForCharacter(run, 2);
+ len[3] = font.PixelOffsetForCharacter(run, 3);
+ len[4] = font.PixelOffsetForCharacter(run, 4);
+ len[5] = font.PixelOffsetForCharacter(run, 5);
+
+ // First three chars should be increasing.
+ ASSERT_TRUE(len[0] >= 0);
+ ASSERT_TRUE(len[1] > len[0]);
+ ASSERT_TRUE(len[3] > len[1]);
+ ASSERT_TRUE(len[2] > len[3]);
+ ASSERT_TRUE(len[4] > len[2]);
+ ASSERT_TRUE(len[5] > len[4]);
+
+ // Test the same sequence with force LTR. The offsets should appear in
+ // sequence.
+ pp::BrowserFontTextRun forced_run(mixed, false, true);
+ len[0] = font.PixelOffsetForCharacter(forced_run, 0);
+ len[1] = font.PixelOffsetForCharacter(forced_run, 1);
+ len[2] = font.PixelOffsetForCharacter(forced_run, 2);
+ len[3] = font.PixelOffsetForCharacter(forced_run, 3);
+ len[4] = font.PixelOffsetForCharacter(forced_run, 4);
+ len[5] = font.PixelOffsetForCharacter(forced_run, 5);
+ for (int i = 1; i < kNumChars; i++)
+ ASSERT_TRUE(len[i] > len[i - 1]);
+
+ PASS();
+}
+
// Tests that the character/pixel offset functions correctly round-trip.
std::string TestBrowserFont::TestCharPos() {
pp::BrowserFontDescription desc;
@@ -71,6 +115,48 @@ std::string TestBrowserFont::TestCharPos() {
PASS();
}
+// Tests that we can get character positions in a mixed LTR/RTL run.
+std::string TestBrowserFont::TestCharPosRTL() {
+ pp::BrowserFontDescription desc;
+ pp::BrowserFont_Trusted font(instance_, desc);
+
+ // Mixed string, two chars of LTR, two of RTL, than two of LTR.
+ // Note this is in UTF-8 so has more than 6 bytes.
+ std::string mixed("AB\xd7\x94\xd7\x97ZZ");
+
+ pp::BrowserFontTextRun run(mixed);
+ static const int kNumChars = 6;
+ int expected_char_sequence[kNumChars] = { 0, 1, 3, 2, 4, 5 };
+
+ // Check that the characters appear in the order we expect.
+ int pixel_width = font.MeasureText(pp::BrowserFontTextRun(mixed));
+ int last_sequence = 0; // Index into expected_char_sequence.
+ for (int x = 0; x < pixel_width; x++) {
+ int cur_char = font.CharacterOffsetForPixel(run, x);
+ if (cur_char != expected_char_sequence[last_sequence]) {
+ // This pixel has a different character. It should be the next one in
+ // the sequence for it to be correct.
+ last_sequence++;
+ ASSERT_TRUE(last_sequence < kNumChars);
+ ASSERT_TRUE(cur_char == expected_char_sequence[last_sequence]);
+ }
+ }
+
+ // Try the same string with force LTR. The characters should all appear in
+ // sequence.
+ pp::BrowserFontTextRun forced_run(mixed, false, true);
+ int last_forced_char = 0; // Char index into the forced sequence.
+ for (int x = 0; x < pixel_width; x++) {
+ int cur_char = font.CharacterOffsetForPixel(forced_run, x);
+ if (cur_char != last_forced_char) {
+ last_forced_char++;
+ ASSERT_TRUE(cur_char == last_forced_char);
+ }
+ }
+
+ PASS();
+}
+
// Tests that drawing some text produces "some" output.
std::string TestBrowserFont::TestDraw() {
pp::BrowserFontDescription desc;
diff --git a/ppapi/tests/test_browser_font.h b/ppapi/tests/test_browser_font.h
index eba1c7e..c166212 100644
--- a/ppapi/tests/test_browser_font.h
+++ b/ppapi/tests/test_browser_font.h
@@ -18,7 +18,9 @@ class TestBrowserFont : public TestCase {
private:
std::string TestFontFamilies();
std::string TestMeasure();
+ std::string TestMeasureRTL();
std::string TestCharPos();
+ std::string TestCharPosRTL();
std::string TestDraw();
};