Commit a46fb8ca authored by Paul Asmuth's avatar Paul Asmuth
Browse files

refactor the 'text layout' code so that glyph placement happens before calling...

refactor the 'text layout' code so that glyph placement happens before calling the rendering backend
parent 03987b82
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ struct BrushFillOp {

struct TextSpanOp {
  std::string text;
  Point position;
  std::vector<text::GlyphPlacement> glyphs;
  Point origin;
  double rotate;
  Point rotate_pivot;
  TextStyle style;
+2 −2
Original line number Diff line number Diff line
@@ -91,8 +91,8 @@ Status svg_text_span(
  svg->buffer
    << "  "
    << "<text"
    << svg_attr("x", op.position.x)
    << svg_attr("y", op.position.y)
    << svg_attr("x", op.origin.x)
    << svg_attr("y", op.origin.y)
    << svg_attr("fill", style.color.to_hex_str())
    << svg_attr("font-size", style.font_size)
    << svg_attr("font-family", style.font.font_family_css)
+9 −34
Original line number Diff line number Diff line
@@ -129,43 +129,17 @@ Status Rasterizer::strokePath(const layer_ops::BrushStrokeOp& op) {
}

Status Rasterizer::drawText(const layer_ops::TextSpanOp& op) {
  std::vector<text::GlyphPlacement> glyphs;
  auto rc = text::layoutText(
      op.text,
      op.position.x,
      op.position.y,
      op.style.font,
      op.style.font_size,
      96, // FIXME
      op.style.direction,
      text_shaper.get(),
      [&glyphs] (const text::GlyphPlacement& g) { glyphs.emplace_back(g); });

  if (rc != OK) {
    return rc;
  }

  return drawTextGlyphs(
      glyphs.data(),
      glyphs.size(),
      op.style);
}

Status Rasterizer::drawTextGlyphs(
    const text::GlyphPlacement* glyphs,
    size_t glyph_count,
    const TextStyle& style) {
  if (!ft_ready) {
    return ERROR;
  }

  // FIXME cache
  FT_Face ft_font;
  if (FT_New_Face(ft, style.font.font_file.c_str(), 0, &ft_font)) {
  if (FT_New_Face(ft, op.style.font.font_file.c_str(), 0, &ft_font)) {
    return ERROR;
  }

  auto font_size_ft = style.font_size * (72.0 / dpi) * 64;
  auto font_size_ft = op.style.font_size * (72.0 / dpi) * 64;
  if (FT_Set_Char_Size(ft_font, 0, font_size_ft, dpi, dpi)) {
    FT_Done_Face(ft_font);
    return ERROR;
@@ -173,18 +147,19 @@ Status Rasterizer::drawTextGlyphs(

  cairo_set_source_rgba(
     cr_ctx,
     style.color.red(),
     style.color.green(),
     style.color.blue(),
     style.color.alpha());
     op.style.color.red(),
     op.style.color.green(),
     op.style.color.blue(),
     op.style.color.alpha());

  auto cairo_face = cairo_ft_font_face_create_for_ft_face(ft_font, 0);
  cairo_set_font_face(cr_ctx, cairo_face);
  cairo_set_font_size(cr_ctx, style.font_size);
  cairo_set_font_size(cr_ctx, op.style.font_size);

  auto glyph_count = op.glyphs.size();
  auto cairo_glyphs = cairo_glyph_allocate(glyph_count);
  for (int i = 0; i < glyph_count; ++i) {
    const auto& g = glyphs[i];
    const auto& g = op.glyphs[i];
    //FT_Load_Glyph(ft_font, g.codepoint, FT_LOAD_DEFAULT);

    cairo_glyphs[i].index = g.codepoint;
+12 −3
Original line number Diff line number Diff line
@@ -30,12 +30,15 @@ Status drawTextLabel(
    const TextStyle& style,
    Layer* layer) {
  Rectangle bbox;
  auto rc = text::text_measure_span(
  std::vector<text::GlyphPlacement> glyphs;
  auto rc = text::text_layout(
      text,
      style.font,
      style.font_size,
      layer->dpi,
      96, // FIXME
      style.direction,
      layer->text_shaper.get(),
      &glyphs,
      &bbox);

  auto offset = layout_align(bbox, position, align_x, align_y);
@@ -44,16 +47,22 @@ Status drawTextLabel(
    return rc;
  }

  for (auto& g : glyphs) {
    g.x += offset.x;
    g.y += offset.y;
  }

  StrokeStyle ss;
  ss.line_width = from_px(1.0);
  ss.color = Color::fromRGB(0.5,0.5,0.5);

  layer_ops::TextSpanOp op;
  op.text = text;
  op.position = offset;
  op.rotate = rotate;
  op.rotate_pivot = position;
  op.style = style;
  op.glyphs = std::move(glyphs);
  op.origin = offset;

  return layer->apply(op);
}
+33 −57
Original line number Diff line number Diff line
@@ -18,103 +18,79 @@
namespace fviz {
namespace text {

Status text_measure_span(
Status text_layout_ltr(
    const std::string& text,
    const FontInfo& font_info,
    double font_size,
    double dpi,
    const TextShaper* shaper,
    Rectangle* rect) {
  double line_length = 0;
    std::vector<GlyphPlacement>* glyphs,
    Rectangle* bbox) {
  double line_length = 0.0f;
  double top = 0.0f;
  double bottom = 0.0f;

  std::vector<GlyphInfo> glyphs;
  auto rc = shaper->shapeText(
      text,
      font_info,
      font_size,
      dpi,
      [&] (const GlyphInfo& gi) {
        line_length += gi.advance_x;
        top = std::min(-gi.metrics_ascender, top);
        bottom = std::max(-gi.metrics_descender, bottom);
        glyphs.emplace_back(gi);
      });

  if (rc != OK) {
    return rc;
  }
        GlyphPlacement gp = {
          .codepoint = gi.codepoint,
          .x = line_length,
          .y = 0
        };

  *rect = Rectangle(0, top, line_length, bottom - top);
  return OK;
        if (glyphs) {
          glyphs->emplace_back(gp);
        }

Status layoutTextLTR(
    const std::string& text,
    double x,
    double y,
    const FontInfo& font_info,
    double font_size,
    double dpi,
    const TextShaper* shaper,
    std::function<void (const GlyphPlacement&)> glyph_cb) {
  double line_length;
  std::vector<GlyphInfo> glyphs;
  auto rc = shaper->shapeText(
      text,
      font_info,
      font_size,
      dpi,
      [&] (const GlyphInfo& gi) {
        line_length += gi.advance_x;
        glyphs.emplace_back(gi);
        top = std::min(-gi.metrics_ascender, top);
        bottom = std::max(-gi.metrics_descender, bottom);
      });

  if (rc != OK) {
    return rc;
  }

  auto gx = x;
  auto gy = y;


  for (const auto& gi : glyphs) {
    double baseline_offset = 0;

    GlyphPlacement g;
    glyph_cb(GlyphPlacement {
      .codepoint = gi.codepoint,
      .x = gx,
      .y = gy + baseline_offset
    });

    gx += gi.advance_x;
  }
  *bbox = Rectangle(
      0,
      top,
      line_length,
      bottom - top);

  return OK;
}

Status layoutText(

Status text_layout(
    const std::string& text,
    double x,
    double y,
    const FontInfo& font,
    double font_size,
    double dpi,
    TextDirection direction,
    const TextShaper* shaper,
    std::function<void (const GlyphPlacement&)> glyph_cb) {
    std::vector<GlyphPlacement>* glyphs,
    Rectangle* bbox) {
  switch (direction) {
    case TextDirection::LTR:
      return layoutTextLTR(text, x, y, font, font_size, dpi, shaper, glyph_cb);
    case TextDirection::RTL:
      return ERROR;
      return text_layout_ltr(text, font, font_size, dpi, shaper, glyphs, bbox);
    default:
      return ERROR;
  }
}

Status text_measure_span(
    const std::string& text,
    const FontInfo& font_info,
    double font_size,
    double dpi,
    const TextShaper* shaper,
    Rectangle* bbox) {
  return text_layout_ltr(text, font_info, font_size, dpi, shaper, nullptr, bbox);
}

} // namespace text
} // namespace fviz
Loading