blob: c4a6871ad79e8c61b49d19d93369cb1d69ab33d0 [file] [log] [blame] [edit]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/skia/modules/skparagraph/include/Paragraph.h"
#include "flutter/skwasm/export.h"
#include "flutter/skwasm/live_objects.h"
#include "flutter/skwasm/text/text_types.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "third_party/skia/modules/skparagraph/include/DartTypes.h"
#include "third_party/skia/modules/skparagraph/include/TextStyle.h"
SKWASM_EXPORT void paragraph_dispose(Skwasm::Paragraph* paragraph) {
Skwasm::live_paragraph_count--;
delete paragraph;
}
SKWASM_EXPORT SkScalar paragraph_getWidth(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getMaxWidth();
}
SKWASM_EXPORT SkScalar paragraph_getHeight(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getHeight();
}
SKWASM_EXPORT SkScalar paragraph_getLongestLine(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getLongestLine();
}
SKWASM_EXPORT SkScalar
paragraph_getMinIntrinsicWidth(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getMinIntrinsicWidth();
}
SKWASM_EXPORT SkScalar
paragraph_getMaxIntrinsicWidth(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getMaxIntrinsicWidth();
}
SKWASM_EXPORT SkScalar
paragraph_getAlphabeticBaseline(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getAlphabeticBaseline();
}
SKWASM_EXPORT SkScalar
paragraph_getIdeographicBaseline(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->getIdeographicBaseline();
}
SKWASM_EXPORT bool paragraph_getDidExceedMaxLines(
Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->didExceedMaxLines();
}
SKWASM_EXPORT void paragraph_layout(Skwasm::Paragraph* paragraph,
SkScalar width) {
paragraph->skia_paragraph->layout(width);
}
SKWASM_EXPORT int32_t
paragraph_getPositionForOffset(Skwasm::Paragraph* paragraph,
SkScalar offset_x,
SkScalar offset_y,
skia::textlayout::Affinity* out_affinity) {
auto position = paragraph->skia_paragraph->getGlyphPositionAtCoordinate(
offset_x, offset_y);
if (out_affinity) {
*out_affinity = position.affinity;
}
return position.position;
}
SKWASM_EXPORT bool paragraph_getClosestGlyphInfoAtCoordinate(
Skwasm::Paragraph* paragraph,
SkScalar offset_x,
SkScalar offset_y,
// Out parameters:
SkRect* grapheme_layout_bounds, // 1 SkRect
size_t* grapheme_code_unit_range, // 2 size_ts: [start, end]
bool* boolean_flags) { // 1 boolean: isLTR
skia::textlayout::Paragraph::GlyphInfo glyph_info;
if (!paragraph->skia_paragraph->getClosestUTF16GlyphInfoAt(offset_x, offset_y,
&glyph_info)) {
return false;
}
// This is more verbose than memcpying the whole struct but ideally we don't
// want to depend on the exact memory layout of the struct.
std::memcpy(grapheme_layout_bounds, &glyph_info.fGraphemeLayoutBounds,
sizeof(SkRect));
std::memcpy(grapheme_code_unit_range, &glyph_info.fGraphemeClusterTextRange,
2 * sizeof(size_t));
boolean_flags[0] =
glyph_info.fDirection == skia::textlayout::TextDirection::kLtr;
return true;
}
SKWASM_EXPORT bool paragraph_getGlyphInfoAt(
Skwasm::Paragraph* paragraph,
size_t index,
// Out parameters:
SkRect* grapheme_layout_bounds, // 1 SkRect
size_t* grapheme_code_unit_range, // 2 size_ts: [start, end]
bool* boolean_flags) { // 1 boolean: isLTR
skia::textlayout::Paragraph::GlyphInfo glyph_info;
if (!paragraph->skia_paragraph->getGlyphInfoAtUTF16Offset(index,
&glyph_info)) {
return false;
}
std::memcpy(grapheme_layout_bounds, &glyph_info.fGraphemeLayoutBounds,
sizeof(SkRect));
std::memcpy(grapheme_code_unit_range, &glyph_info.fGraphemeClusterTextRange,
2 * sizeof(size_t));
boolean_flags[0] =
glyph_info.fDirection == skia::textlayout::TextDirection::kLtr;
return true;
}
SKWASM_EXPORT void paragraph_getWordBoundary(
Skwasm::Paragraph* paragraph,
unsigned int position,
int32_t* out_range // Two `int32_t`s, start and end
) {
auto range = paragraph->skia_paragraph->getWordBoundary(position);
out_range[0] = range.start;
out_range[1] = range.end;
}
SKWASM_EXPORT size_t paragraph_getLineCount(Skwasm::Paragraph* paragraph) {
return paragraph->skia_paragraph->lineNumber();
}
SKWASM_EXPORT int paragraph_getLineNumberAt(Skwasm::Paragraph* paragraph,
size_t character_index) {
return paragraph->skia_paragraph->getLineNumberAtUTF16Offset(character_index);
}
SKWASM_EXPORT skia::textlayout::LineMetrics* paragraph_getLineMetricsAtIndex(
Skwasm::Paragraph* paragraph,
size_t line_number) {
Skwasm::live_line_metrics_count++;
auto metrics = new skia::textlayout::LineMetrics();
if (paragraph->skia_paragraph->getLineMetricsAt(line_number, metrics)) {
return metrics;
} else {
delete metrics;
return nullptr;
}
}
struct TextBoxList {
std::vector<skia::textlayout::TextBox> boxes;
};
SKWASM_EXPORT void textBoxList_dispose(TextBoxList* list) {
Skwasm::live_text_box_list_count--;
delete list;
}
SKWASM_EXPORT size_t textBoxList_getLength(TextBoxList* list) {
return list->boxes.size();
}
SKWASM_EXPORT skia::textlayout::TextDirection
textBoxList_getBoxAtIndex(TextBoxList* list, size_t index, SkRect* out_rect) {
const auto& box = list->boxes[index];
*out_rect = box.rect;
return box.direction;
}
SKWASM_EXPORT TextBoxList* paragraph_getBoxesForRange(
Skwasm::Paragraph* paragraph,
int start,
int end,
skia::textlayout::RectHeightStyle height_style,
skia::textlayout::RectWidthStyle width_style) {
Skwasm::live_text_box_list_count++;
return new TextBoxList{paragraph->skia_paragraph->getRectsForRange(
start, end, height_style, width_style)};
}
SKWASM_EXPORT TextBoxList* paragraph_getBoxesForPlaceholders(
Skwasm::Paragraph* paragraph) {
Skwasm::live_text_box_list_count++;
return new TextBoxList{paragraph->skia_paragraph->getRectsForPlaceholders()};
}
// Returns a list of the code points that were unable to be rendered with the
// selected fonts. The list is deduplicated, so each code point in the output
// is unique.
// If `nullptr` is passed in for `outCodePoints`, we simply return the count
// of the code points.
// Note: This must be called after the paragraph has been laid out at least
// once in order to get valid data.
SKWASM_EXPORT int paragraph_getUnresolvedCodePoints(
Skwasm::Paragraph* paragraph,
SkUnichar* out_code_points,
int out_length) {
if (!out_code_points) {
return paragraph->skia_paragraph->unresolvedCodepoints().size();
}
int out_index = 0;
for (SkUnichar character :
paragraph->skia_paragraph->unresolvedCodepoints()) {
if (out_index < out_length) {
out_code_points[out_index] = character;
out_index++;
} else {
break;
}
}
return out_index;
}