Commit 33c442ca authored by Paul Asmuth's avatar Paul Asmuth
Browse files

add support for RTL text layout

parent f43a55e7
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -43,6 +43,15 @@ Status drawTextLabel(
    const TextStyle& text_style,
    Layer* layer);

Status drawTextLabel(
    const std::string& text,
    const Point& position,
    HAlign align_x,
    VAlign align_y,
    double rotate,
    const TextStyle& text_style,
    Layer* layer);

Status drawTextLabel(
    const std::string& text,
    const Point& position,
+34 −15
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ Status text_layout_hspan(
  std::vector<GlyphInfo> glyph_list;
  auto shaping_rc = text_shape_with_font_fallback(
      text,
      text_direction,
      font_info,
      font_size,
      dpi,
@@ -38,15 +39,22 @@ Status text_layout_hspan(
    return shaping_rc;
  }

  double line_length = 0.0f;
  double line_top = 0.0f;
  double line_bottom = 0.0f;
  double span_length = 0.0;
  double span_top = 0.0;
  double span_bottom = 0.0;
  for (const auto& gi : glyph_list) {
    GlyphPlacement gp = {
      .codepoint = gi.codepoint,
      .x = line_length,
      .y = 0
    };
    GlyphPlacement gp;
    gp.codepoint = gi.codepoint;
    gp.y = 0;

    switch (text_direction) {
      case TextDirection::LTR:
        gp.x = span_length;
        break;
      case TextDirection::RTL:
        gp.x = -span_length - gi.advance_x;
        break;
    }

    GlyphSpan span;
    span.font = gi.font;
@@ -57,16 +65,27 @@ Status text_layout_hspan(
      glyph_spans->emplace_back(span);
    }

    line_length += gi.advance_x;
    line_top = std::min(-gi.metrics_ascender, line_top);
    line_bottom = std::max(-gi.metrics_descender, line_bottom);
    span_length += gi.advance_x;
    span_top = std::min(-gi.metrics_ascender, span_top);
    span_bottom = std::max(-gi.metrics_descender, span_bottom);
  }


  double span_left = 0.0;
  switch (text_direction) {
    case TextDirection::LTR:
      span_left = 0;
      break;
    case TextDirection::RTL:
      span_left = -span_length;
      break;
  }

  *bbox = Rectangle(
      0,
      line_top,
      line_length,
      line_bottom - line_top);
      span_left,
      span_top,
      span_length,
      span_bottom - span_top);

  return OK;
}
+11 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ namespace text {

Status text_shape(
    const std::string& text,
    TextDirection text_direction,
    FontRef font,
    double font_size,
    double dpi,
@@ -40,8 +41,14 @@ Status text_shape(
  auto hb_font = hb_ft_font_create_referenced(ft_font);

  hb_buffer_reset(hb_buf);
  switch (text_direction) {
    case TextDirection::LTR:
      hb_buffer_set_direction(hb_buf, HB_DIRECTION_LTR);
  hb_buffer_set_script(hb_buf, HB_SCRIPT_LATIN);
      break;
    case TextDirection::RTL:
      hb_buffer_set_direction(hb_buf, HB_DIRECTION_RTL);
      break;
  }

  hb_buffer_add_utf8(hb_buf, text.data(), text.size(), 0, text.size());
  hb_shape(hb_font, hb_buf, NULL, 0);
@@ -67,6 +74,7 @@ Status text_shape(

Status text_shape_with_font_fallback(
    const std::string& text,
    TextDirection dir,
    const FontInfo& font_info,
    double font_size,
    double dpi,
@@ -87,7 +95,7 @@ Status text_shape_with_font_fallback(
    for (const auto& font : font_info.fonts) {
      grapheme_glyphs.clear();

      auto rc = text_shape(grapheme, font, font_size, dpi, &grapheme_glyphs);
      auto rc = text_shape(grapheme, dir, font, font_size, dpi, &grapheme_glyphs);
      if (rc != OK) {
        return rc;
      }
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct GlyphInfo {

Status text_shape(
    const std::string& text,
    TextDirection text_direction,
    FontRef font,
    double font_size,
    double dpi,
@@ -45,6 +46,7 @@ Status text_shape(

Status text_shape_with_font_fallback(
    const std::string& text,
    TextDirection text_direction,
    const FontInfo& font_info,
    double font_size,
    double dpi,
+34 −17
Original line number Diff line number Diff line
@@ -27,48 +27,65 @@ void draw_test(
    const FontInfo& font,
    uint32_t x,
    uint32_t y,
    TextDirection dir,
    HAlign ax,
    VAlign ay) {
  TextStyle ts;
  ts.font = font;
  ts.font_size = from_unit(64);
  ts.font_size = from_unit(32);
  ts.color = Color::fromRGB(0,0,0);
  ts.direction = dir;

  StrokeStyle ss;
  ss.line_width = from_unit(1);

  strokeLine(l, Point(x - 10, y), Point(x + 10, y), ss);
  strokeLine(l, Point(x, y - 10), Point(x, y + 10), ss);
  drawTextLabel("Fnord!", Point(x, y), ax, ay, ts, l);
  drawTextLabel("Hello תל אביב !", Point(x, y), ax, ay, 0, ts, l);
}

void draw_test(Layer* layer, const FontInfo& font) {
  draw_test(layer, font, 100 * 2,  100 * 2, HAlign::LEFT, VAlign::TOP);
  draw_test(layer, font, 400 * 2,  100 * 2, HAlign::CENTER, VAlign::TOP);
  draw_test(layer, font, 700 * 2,  100 * 2, HAlign::RIGHT, VAlign::TOP);
  draw_test(layer, font, 100 * 2,  100 * 2, TextDirection::LTR, HAlign::LEFT, VAlign::TOP);
  draw_test(layer, font, 400 * 2,  100 * 2, TextDirection::LTR, HAlign::CENTER, VAlign::TOP);
  draw_test(layer, font, 700 * 2,  100 * 2, TextDirection::LTR, HAlign::RIGHT, VAlign::TOP);

  draw_test(layer, font, 100 * 2,  200 * 2, HAlign::LEFT, VAlign::CENTER);
  draw_test(layer, font, 400 * 2,  200 * 2, HAlign::CENTER, VAlign::CENTER);
  draw_test(layer, font, 700 * 2,  200 * 2, HAlign::RIGHT, VAlign::CENTER);
  draw_test(layer, font, 100 * 2,  200 * 2, TextDirection::LTR, HAlign::LEFT, VAlign::CENTER);
  draw_test(layer, font, 400 * 2,  200 * 2, TextDirection::LTR, HAlign::CENTER, VAlign::CENTER);
  draw_test(layer, font, 700 * 2,  200 * 2, TextDirection::LTR, HAlign::RIGHT, VAlign::CENTER);

  draw_test(layer, font, 100 * 2,  300 * 2, TextDirection::LTR, HAlign::LEFT, VAlign::BOTTOM);
  draw_test(layer, font, 400 * 2,  300 * 2, TextDirection::LTR, HAlign::CENTER, VAlign::BOTTOM);
  draw_test(layer, font, 700 * 2,  300 * 2, TextDirection::LTR, HAlign::RIGHT, VAlign::BOTTOM);

  draw_test(layer, font, 100 * 2,  400 * 2, TextDirection::RTL, HAlign::LEFT, VAlign::TOP);
  draw_test(layer, font, 400 * 2,  400 * 2, TextDirection::RTL, HAlign::CENTER, VAlign::TOP);
  draw_test(layer, font, 700 * 2,  400 * 2, TextDirection::RTL, HAlign::RIGHT, VAlign::TOP);

  draw_test(layer, font, 100 * 2,  500 * 2, TextDirection::RTL, HAlign::LEFT, VAlign::CENTER);
  draw_test(layer, font, 400 * 2,  500 * 2, TextDirection::RTL, HAlign::CENTER, VAlign::CENTER);
  draw_test(layer, font, 700 * 2,  500 * 2, TextDirection::RTL, HAlign::RIGHT, VAlign::CENTER);

  draw_test(layer, font, 100 * 2,  600 * 2, TextDirection::RTL, HAlign::LEFT, VAlign::BOTTOM);
  draw_test(layer, font, 400 * 2,  600 * 2, TextDirection::RTL, HAlign::CENTER, VAlign::BOTTOM);
  draw_test(layer, font, 700 * 2,  600 * 2, TextDirection::RTL, HAlign::RIGHT, VAlign::BOTTOM);

  draw_test(layer, font, 100 * 2,  300 * 2, HAlign::LEFT, VAlign::BOTTOM);
  draw_test(layer, font, 400 * 2,  300 * 2, HAlign::CENTER, VAlign::BOTTOM);
  draw_test(layer, font, 700 * 2,  300 * 2, HAlign::RIGHT, VAlign::BOTTOM);
}

int main(int argc, char** argv) {
  FontRef font_ref;
  EXPECT_OK(font_load("/usr/share/fonts/msttcore/comic.ttf", &font_ref));
  FontRef font_ref1;
  EXPECT_OK(font_load("/usr/share/fonts/msttcore/arial.ttf", &font_ref1));

  FontRef font_ref2;
  EXPECT_OK(font_load("/usr/share/fonts/msttcore/comic.ttf", &font_ref2));

  FontInfo font;
  font.font_family_css = "'Comic Sans MS'";
  font.fonts = {font_ref};
  font.fonts = {font_ref2, font_ref1};

  {
    LayerRef layer;
    auto rc = layer_bind_svg(
        1600,
        1000,
        1400,
        96,
        from_unit(12),
        Color::fromRGB(1.0, 1.0, 1.0),
@@ -86,7 +103,7 @@ int main(int argc, char** argv) {
    LayerRef layer;
    auto rc = layer_bind_png(
        1600,
        1000,
        1400,
        96,
        from_unit(12),
        Color::fromRGB(1.0, 1.0, 1.0),