[Impeller] libImpeller: Implement APIs for fetching glyph and line metrics. (#165701)

This patch adds support in the typography subsystem of the public
Impeller API such that users can implement text editing functionality.

* Line metrics for a fully laid out paragraph can be retrieved. The
metrics contain information about offsets into the original code unit
buffer used to create the paragraph. These offsets can be used to
implement functionality that edits whole lines.
* Glyph information for a specific code unit offset, as well as a
coordinate offset relative to the paragraph origin, can be obtained.
This information can be used place decorations (like carets), select
words surrounding the caret (a hit-test), and edit the source buffer to
re-layout the paragraph.
* Word boundaries (as specified in Unicode Standard Annex 29) can be
retrieved to select and modify paragraph subsets by character, word, and
line at caret.

Like in Flutter, the code unit buffers are assumed to be arrays of
UTF-16 bytes. I'd have preferred this to be UTF-8 because the initial
paragraph construction is using UTF-8 bytes. Also, Skia internally seems
to work with UTF-8 too but the interfaces are exposed using UTF-16
(presumably for users like Flutter that work with Dart strings that are
UTF-16). Exposing additional APIs in txt::Paragraph to back this out
seemed onerous. Instead, a UTF-16 assumption for all APIs that retrieve
metrics is made (and documented). It stands to reason that paragraphs
should be constructable using UTF-16 buffers in the public API too. I'll
add that in a subsequent patch as that has little to do with metrics.

Fixes https://github.com/flutter/flutter/issues/165509
This commit is contained in:
Chinmay Garde 2025-03-26 10:34:14 -07:00 committed by GitHub
parent 9e829cbd92
commit 39103d9512
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1291 additions and 144 deletions

View File

@ -51763,6 +51763,8 @@ ORIGIN: ../../../flutter/impeller/toolkit/interop/example_mtl.m + ../../../flutt
ORIGIN: ../../../flutter/impeller/toolkit/interop/example_vk.c + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/formats.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/formats.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/glyph_info.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/glyph_info.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/image_filter.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/image_filter.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/impeller.cc + ../../../flutter/LICENSE
@ -51770,6 +51772,8 @@ ORIGIN: ../../../flutter/impeller/toolkit/interop/impeller.h + ../../../flutter/
ORIGIN: ../../../flutter/impeller/toolkit/interop/impeller.hpp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/impeller_c.c + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/impeller_cc.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/line_metrics.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/line_metrics.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/mask_filter.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/mask_filter.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/toolkit/interop/object.cc + ../../../flutter/LICENSE
@ -54745,6 +54749,8 @@ FILE: ../../../flutter/impeller/toolkit/interop/example_mtl.m
FILE: ../../../flutter/impeller/toolkit/interop/example_vk.c
FILE: ../../../flutter/impeller/toolkit/interop/formats.cc
FILE: ../../../flutter/impeller/toolkit/interop/formats.h
FILE: ../../../flutter/impeller/toolkit/interop/glyph_info.cc
FILE: ../../../flutter/impeller/toolkit/interop/glyph_info.h
FILE: ../../../flutter/impeller/toolkit/interop/image_filter.cc
FILE: ../../../flutter/impeller/toolkit/interop/image_filter.h
FILE: ../../../flutter/impeller/toolkit/interop/impeller.cc
@ -54752,6 +54758,8 @@ FILE: ../../../flutter/impeller/toolkit/interop/impeller.h
FILE: ../../../flutter/impeller/toolkit/interop/impeller.hpp
FILE: ../../../flutter/impeller/toolkit/interop/impeller_c.c
FILE: ../../../flutter/impeller/toolkit/interop/impeller_cc.cc
FILE: ../../../flutter/impeller/toolkit/interop/line_metrics.cc
FILE: ../../../flutter/impeller/toolkit/interop/line_metrics.h
FILE: ../../../flutter/impeller/toolkit/interop/mask_filter.cc
FILE: ../../../flutter/impeller/toolkit/interop/mask_filter.h
FILE: ../../../flutter/impeller/toolkit/interop/object.cc

View File

@ -41,8 +41,12 @@ impeller_component("interop_base") {
"dl_builder.h",
"formats.cc",
"formats.h",
"glyph_info.cc",
"glyph_info.h",
"image_filter.cc",
"image_filter.h",
"line_metrics.cc",
"line_metrics.h",
"mask_filter.cc",
"mask_filter.h",
"object.cc",

View File

@ -0,0 +1,42 @@
// 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 "impeller/toolkit/interop/glyph_info.h"
namespace impeller::interop {
GlyphInfo::~GlyphInfo() = default;
size_t GlyphInfo::GetGraphemeClusterCodeUnitRangeBegin() const {
return info_.fGraphemeClusterTextRange.start;
}
size_t GlyphInfo::GetGraphemeClusterCodeUnitRangeEnd() const {
return info_.fGraphemeClusterTextRange.end;
}
ImpellerRect GlyphInfo::GetGraphemeClusterBounds() const {
return ImpellerRect{
info_.fGraphemeLayoutBounds.y(),
info_.fGraphemeLayoutBounds.x(),
info_.fGraphemeLayoutBounds.width(),
info_.fGraphemeLayoutBounds.height(),
};
}
bool GlyphInfo::IsEllipsis() const {
return info_.fIsEllipsis;
}
ImpellerTextDirection GlyphInfo::GetTextDirection() const {
switch (info_.fDirection) {
case skia::textlayout::TextDirection::kRtl:
return kImpellerTextDirectionRTL;
case skia::textlayout::TextDirection::kLtr:
return kImpellerTextDirectionLTR;
}
return kImpellerTextDirectionLTR;
}
} // namespace impeller::interop

View File

@ -0,0 +1,63 @@
// 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.
#ifndef FLUTTER_IMPELLER_TOOLKIT_INTEROP_GLYPH_INFO_H_
#define FLUTTER_IMPELLER_TOOLKIT_INTEROP_GLYPH_INFO_H_
#include "flutter/third_party/skia/modules/skparagraph/include/Paragraph.h"
#include "impeller/toolkit/interop/impeller.h"
#include "impeller/toolkit/interop/object.h"
namespace impeller::interop {
//------------------------------------------------------------------------------
/// @brief Internal C++ peer of ImpellerGlyphInfo. For detailed
/// documentation, refer to the headerdocs in the public API in
/// impeller.h.
///
class GlyphInfo final
: public Object<GlyphInfo,
IMPELLER_INTERNAL_HANDLE_NAME(ImpellerGlyphInfo)> {
public:
explicit GlyphInfo(skia::textlayout::Paragraph::GlyphInfo info)
: info_(info) {}
~GlyphInfo();
GlyphInfo(const GlyphInfo&) = delete;
GlyphInfo& operator=(const GlyphInfo&) = delete;
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin.
///
size_t GetGraphemeClusterCodeUnitRangeBegin() const;
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd.
///
size_t GetGraphemeClusterCodeUnitRangeEnd() const;
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterBounds.
///
ImpellerRect GetGraphemeClusterBounds() const;
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoIsEllipsis.
///
bool IsEllipsis() const;
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetTextDirection.
///
ImpellerTextDirection GetTextDirection() const;
private:
const skia::textlayout::Paragraph::GlyphInfo info_;
};
} // namespace impeller::interop
#endif // FLUTTER_IMPELLER_TOOLKIT_INTEROP_GLYPH_INFO_H_

View File

@ -17,7 +17,9 @@
#include "impeller/toolkit/interop/context.h"
#include "impeller/toolkit/interop/dl_builder.h"
#include "impeller/toolkit/interop/formats.h"
#include "impeller/toolkit/interop/glyph_info.h"
#include "impeller/toolkit/interop/image_filter.h"
#include "impeller/toolkit/interop/line_metrics.h"
#include "impeller/toolkit/interop/mask_filter.h"
#include "impeller/toolkit/interop/object.h"
#include "impeller/toolkit/interop/paint.h"
@ -58,7 +60,9 @@ DEFINE_PEER_GETTER(ColorSource, ImpellerColorSource);
DEFINE_PEER_GETTER(Context, ImpellerContext);
DEFINE_PEER_GETTER(DisplayList, ImpellerDisplayList);
DEFINE_PEER_GETTER(DisplayListBuilder, ImpellerDisplayListBuilder);
DEFINE_PEER_GETTER(GlyphInfo, ImpellerGlyphInfo);
DEFINE_PEER_GETTER(ImageFilter, ImpellerImageFilter);
DEFINE_PEER_GETTER(LineMetrics, ImpellerLineMetrics);
DEFINE_PEER_GETTER(MaskFilter, ImpellerMaskFilter);
DEFINE_PEER_GETTER(Paint, ImpellerPaint);
DEFINE_PEER_GETTER(Paragraph, ImpellerParagraph);
@ -1272,6 +1276,12 @@ uint32_t ImpellerParagraphGetLineCount(ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetLineCount();
}
IMPELLER_EXTERN_C
ImpellerRange ImpellerParagraphGetWordBoundary(ImpellerParagraph paragraph,
size_t code_unit_index) {
return GetPeer(paragraph)->GetWordBoundary(code_unit_index);
}
IMPELLER_EXTERN_C
ImpellerTypographyContext ImpellerTypographyContextNew() {
auto context = Create<TypographyContext>();
@ -1309,4 +1319,154 @@ bool ImpellerTypographyContextRegisterFont(ImpellerTypographyContext context,
family_name_alias);
}
IMPELLER_EXTERN_C
ImpellerLineMetrics ImpellerParagraphGetLineMetrics(
ImpellerParagraph paragraph) {
return GetPeer(paragraph)->GetLineMetrics().GetC();
}
IMPELLER_EXTERN_C
ImpellerGlyphInfo ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew(
ImpellerParagraph paragraph,
size_t code_unit_index) {
return GetPeer(paragraph)
->GetGlyphInfoAtCodeUnitIndex(code_unit_index)
.Leak();
}
IMPELLER_EXTERN_C
ImpellerGlyphInfo ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew(
ImpellerParagraph paragraph,
double x,
double y) {
return GetPeer(paragraph)
->GetClosestGlyphInfoAtParagraphCoordinates(x, y)
.Leak();
}
//------------------------------------------------------------------------------
// Line Metrics
//------------------------------------------------------------------------------
IMPELLER_EXTERN_C
void ImpellerLineMetricsRetain(ImpellerLineMetrics line_metrics) {
ObjectBase::SafeRetain(line_metrics);
}
IMPELLER_EXTERN_C
void ImpellerLineMetricsRelease(ImpellerLineMetrics line_metrics) {
ObjectBase::SafeRelease(line_metrics);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetUnscaledAscent(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetUnscaledAscent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetAscent(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetAscent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetDescent(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetDescent(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetBaseline(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetBaseline(line);
}
IMPELLER_EXTERN_C
bool ImpellerLineMetricsIsHardbreak(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->IsHardbreak(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetWidth(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetWidth(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetHeight(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetHeight(line);
}
IMPELLER_EXTERN_C
double ImpellerLineMetricsGetLeft(ImpellerLineMetrics metrics, size_t line) {
return GetPeer(metrics)->GetLeft(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitStartIndex(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitStartIndex(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndex(ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndex(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace(
ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndexExcludingWhitespace(line);
}
IMPELLER_EXTERN_C
size_t ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline(
ImpellerLineMetrics metrics,
size_t line) {
return GetPeer(metrics)->GetCodeUnitEndIndexIncludingNewline(line);
}
//------------------------------------------------------------------------------
// Glyph Info
//------------------------------------------------------------------------------
IMPELLER_EXTERN_C
void ImpellerGlyphInfoRetain(ImpellerGlyphInfo glyph_info) {
ObjectBase::SafeRetain(glyph_info);
}
IMPELLER_EXTERN_C
void ImpellerGlyphInfoRelease(ImpellerGlyphInfo glyph_info) {
ObjectBase::SafeRelease(glyph_info);
}
IMPELLER_EXTERN_C
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetGraphemeClusterCodeUnitRangeBegin();
}
IMPELLER_EXTERN_C
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetGraphemeClusterCodeUnitRangeEnd();
}
IMPELLER_EXTERN_C
ImpellerRect ImpellerGlyphInfoGetGraphemeClusterBounds(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetGraphemeClusterBounds();
}
IMPELLER_EXTERN_C
bool ImpellerGlyphInfoIsEllipsis(ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->IsEllipsis();
}
IMPELLER_EXTERN_C
ImpellerTextDirection ImpellerGlyphInfoGetTextDirection(
ImpellerGlyphInfo glyph_info) {
return GetPeer(glyph_info)->GetTextDirection();
}
} // namespace impeller::interop

View File

@ -246,6 +246,20 @@ IMPELLER_DEFINE_HANDLE(ImpellerParagraphBuilder);
///
IMPELLER_DEFINE_HANDLE(ImpellerParagraphStyle);
//------------------------------------------------------------------------------
/// Describes the metrics of lines in a fully laid out paragraph.
///
/// Regardless of how the string of text is specified to the paragraph builder,
/// offsets into buffers that are returned by line metrics are always assumed to
/// be into buffers of UTF-16 code units.
///
IMPELLER_DEFINE_HANDLE(ImpellerLineMetrics);
//------------------------------------------------------------------------------
/// Describes the metrics of glyphs in a paragraph line.
///
IMPELLER_DEFINE_HANDLE(ImpellerGlyphInfo);
//------------------------------------------------------------------------------
/// Represents a two-dimensional path that is immutable and graphics context
/// agnostic.
@ -483,6 +497,11 @@ typedef struct ImpellerISize {
int64_t height;
} ImpellerISize;
typedef struct ImpellerRange {
uint64_t start;
uint64_t end;
} ImpellerRange;
//------------------------------------------------------------------------------
/// A 4x4 transformation matrix using column-major storage.
///
@ -2610,6 +2629,335 @@ IMPELLER_EXPORT
uint32_t ImpellerParagraphGetLineCount(
ImpellerParagraph IMPELLER_NONNULL paragraph);
//------------------------------------------------------------------------------
/// @brief Get the range into the UTF-16 code unit buffer that represents
/// the word at the specified caret location in the same buffer.
///
/// Word boundaries are defined more precisely in [Unicode Standard
/// Annex #29](http://www.unicode.org/reports/tr29/#Word_Boundaries)
///
/// @param[in] paragraph The paragraph
/// @param[in] code_unit_index The code unit index
///
/// @return The impeller range.
///
IMPELLER_EXPORT
ImpellerRange ImpellerParagraphGetWordBoundary(
ImpellerParagraph IMPELLER_NONNULL paragraph,
size_t code_unit_index);
//------------------------------------------------------------------------------
/// @brief Get the line metrics of this laid out paragraph. Calculating the
/// line metrics is expensive. The first time line metrics are
/// requested, they will be cached along with the paragraph (which
/// is immutable).
///
/// @param[in] paragraph The paragraph.
///
/// @return The line metrics.
///
IMPELLER_EXPORT
ImpellerLineMetrics IMPELLER_NULLABLE ImpellerParagraphGetLineMetrics(
ImpellerParagraph IMPELLER_NONNULL paragraph);
//------------------------------------------------------------------------------
/// @brief Create a new instance of glyph info that can be queried for
/// information about the glyph at the given UTF-16 code unit index.
/// The instance must be freed using `ImpellerGlyphInfoRelease`.
///
/// @param[in] paragraph The paragraph.
/// @param[in] code_unit_index The UTF-16 code unit index.
///
/// @return The glyph information.
///
IMPELLER_EXPORT
IMPELLER_NODISCARD ImpellerGlyphInfo IMPELLER_NULLABLE
ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew(
ImpellerParagraph IMPELLER_NONNULL paragraph,
size_t code_unit_index);
//------------------------------------------------------------------------------
/// @brief Create a new instance of glyph info that can be queried for
/// information about the glyph closest to the specified coordinates
/// relative to the origin of the paragraph. The instance must be
/// freed using `ImpellerGlyphInfoRelease`.
///
/// @param[in] paragraph The paragraph.
/// @param[in] x The x coordinate relative to paragraph origin.
/// @param[in] y The x coordinate relative to paragraph origin.
///
/// @return The glyph information.
///
IMPELLER_EXPORT
IMPELLER_NODISCARD ImpellerGlyphInfo IMPELLER_NULLABLE
ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew(
ImpellerParagraph IMPELLER_NONNULL paragraph,
double x,
double y);
//------------------------------------------------------------------------------
// Line Metrics
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// @brief Retain a strong reference to the object. The object can be NULL
/// in which case this method is a no-op.
///
/// @param[in] line_metrics The line metrics.
///
IMPELLER_EXPORT
void ImpellerLineMetricsRetain(
ImpellerLineMetrics IMPELLER_NULLABLE line_metrics);
//------------------------------------------------------------------------------
/// @brief Release a previously retained reference to the object. The
/// object can be NULL in which case this method is a no-op.
///
/// @param[in] line_metrics The line metrics.
///
IMPELLER_EXPORT
void ImpellerLineMetricsRelease(
ImpellerLineMetrics IMPELLER_NULLABLE line_metrics);
//------------------------------------------------------------------------------
/// @brief The rise from the baseline as calculated from the font and style
/// for this line ignoring the height from the text style.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The unscaled ascent.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetUnscaledAscent(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief The rise from the baseline as calculated from the font and style
/// for this line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The ascent.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetAscent(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief The drop from the baseline as calculated from the font and style
/// for this line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The descent.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetDescent(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief The y coordinate of the baseline for this line from the top of
/// the paragraph.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The baseline.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetBaseline(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Used to determine if this line ends with an explicit line break
/// (e.g. '\n') or is the end of the paragraph.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return True if the line is a hard break.
///
IMPELLER_EXPORT
bool ImpellerLineMetricsIsHardbreak(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Width of the line from the left edge of the leftmost glyph to
/// the right edge of the rightmost glyph.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The width.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetWidth(ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Total height of the line from the top edge to the bottom edge.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The height.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetHeight(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief The x coordinate of left edge of the line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The left edge coordinate.
///
IMPELLER_EXPORT
double ImpellerLineMetricsGetLeft(ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Fetch the start index in the buffer of UTF-16 code units used to
/// represent the paragraph line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The UTF-16 code units start index.
///
IMPELLER_EXPORT
size_t ImpellerLineMetricsGetCodeUnitStartIndex(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Fetch the end index in the buffer of UTF-16 code units used to
/// represent the paragraph line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The UTF-16 code units end index.
///
IMPELLER_EXPORT
size_t ImpellerLineMetricsGetCodeUnitEndIndex(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Fetch the end index (excluding whitespace) in the buffer of
/// UTF-16 code units used to represent the paragraph line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The UTF-16 code units end index excluding whitespace.
///
IMPELLER_EXPORT
size_t ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
/// @brief Fetch the end index (including newlines) in the buffer of UTF-16
/// code units used to represent the paragraph line.
///
/// @param[in] metrics The metrics.
/// @param[in] line The line index (zero based).
///
/// @return The UTF-16 code units end index including newlines.
///
IMPELLER_EXPORT
size_t ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline(
ImpellerLineMetrics IMPELLER_NONNULL metrics,
size_t line);
//------------------------------------------------------------------------------
// Glyph Info
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// @brief Retain a strong reference to the object. The object can be NULL
/// in which case this method is a no-op.
///
/// @param[in] glyph_info The glyph information.
///
IMPELLER_EXPORT
void ImpellerGlyphInfoRetain(ImpellerGlyphInfo IMPELLER_NULLABLE glyph_info);
//------------------------------------------------------------------------------
/// @brief Release a previously retained reference to the object. The
/// object can be NULL in which case this method is a no-op.
///
/// @param[in] glyph_info The glyph information.
///
IMPELLER_EXPORT
void ImpellerGlyphInfoRelease(ImpellerGlyphInfo IMPELLER_NULLABLE glyph_info);
//------------------------------------------------------------------------------
/// @brief Fetch the start index in the buffer of UTF-16 code units used to
/// represent the grapheme cluster for a glyph.
///
/// @param[in] glyph_info The glyph information.
///
/// @return The UTF-16 code units start index.
///
IMPELLER_EXPORT
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin(
ImpellerGlyphInfo IMPELLER_NONNULL glyph_info);
//------------------------------------------------------------------------------
/// @brief Fetch the end index in the buffer of UTF-16 code units used to
/// represent the grapheme cluster for a glyph.
///
/// @param[in] glyph_info The glyph information.
///
/// @return The UTF-16 code units end index.
///
IMPELLER_EXPORT
size_t ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd(
ImpellerGlyphInfo IMPELLER_NONNULL glyph_info);
//------------------------------------------------------------------------------
/// @brief Fetch the bounds of the grapheme cluster for the glyph in the
/// coordinate space of the paragraph.
///
/// @param[in] glyph_info The glyph information.
///
/// @return The grapheme cluster bounds.
///
IMPELLER_EXPORT
ImpellerRect ImpellerGlyphInfoGetGraphemeClusterBounds(
ImpellerGlyphInfo IMPELLER_NONNULL glyph_info);
//------------------------------------------------------------------------------
/// @param[in] glyph_info The glyph information.
///
/// @return True if the glyph represents an ellipsis. False otherwise.
///
IMPELLER_EXPORT
bool ImpellerGlyphInfoIsEllipsis(ImpellerGlyphInfo IMPELLER_NONNULL glyph_info);
//------------------------------------------------------------------------------
/// @param[in] glyph_info The glyph information.
///
/// @return The direction of the run that contains the glyph.
///
IMPELLER_EXPORT
ImpellerTextDirection ImpellerGlyphInfoGetTextDirection(
ImpellerGlyphInfo IMPELLER_NONNULL glyph_info);
IMPELLER_EXTERN_C_END
// NOLINTEND(google-objc-function-naming)

View File

@ -44,149 +44,174 @@ struct Proc {
}
};
#define IMPELLER_HPP_EACH_PROC(PROC) \
PROC(ImpellerColorFilterCreateBlendNew) \
PROC(ImpellerColorFilterCreateColorMatrixNew) \
PROC(ImpellerColorFilterRelease) \
PROC(ImpellerColorFilterRetain) \
PROC(ImpellerColorSourceCreateConicalGradientNew) \
PROC(ImpellerColorSourceCreateImageNew) \
PROC(ImpellerColorSourceCreateLinearGradientNew) \
PROC(ImpellerColorSourceCreateRadialGradientNew) \
PROC(ImpellerColorSourceCreateSweepGradientNew) \
PROC(ImpellerColorSourceRelease) \
PROC(ImpellerColorSourceRetain) \
PROC(ImpellerContextCreateMetalNew) \
PROC(ImpellerContextCreateOpenGLESNew) \
PROC(ImpellerContextCreateVulkanNew) \
PROC(ImpellerContextGetVulkanInfo) \
PROC(ImpellerContextRelease) \
PROC(ImpellerContextRetain) \
PROC(ImpellerDisplayListBuilderClipOval) \
PROC(ImpellerDisplayListBuilderClipPath) \
PROC(ImpellerDisplayListBuilderClipRect) \
PROC(ImpellerDisplayListBuilderClipRoundedRect) \
PROC(ImpellerDisplayListBuilderCreateDisplayListNew) \
PROC(ImpellerDisplayListBuilderDrawDashedLine) \
PROC(ImpellerDisplayListBuilderDrawDisplayList) \
PROC(ImpellerDisplayListBuilderDrawLine) \
PROC(ImpellerDisplayListBuilderDrawOval) \
PROC(ImpellerDisplayListBuilderDrawPaint) \
PROC(ImpellerDisplayListBuilderDrawParagraph) \
PROC(ImpellerDisplayListBuilderDrawShadow) \
PROC(ImpellerDisplayListBuilderDrawPath) \
PROC(ImpellerDisplayListBuilderDrawRect) \
PROC(ImpellerDisplayListBuilderDrawRoundedRect) \
PROC(ImpellerDisplayListBuilderDrawRoundedRectDifference) \
PROC(ImpellerDisplayListBuilderDrawTexture) \
PROC(ImpellerDisplayListBuilderDrawTextureRect) \
PROC(ImpellerDisplayListBuilderGetSaveCount) \
PROC(ImpellerDisplayListBuilderGetTransform) \
PROC(ImpellerDisplayListBuilderNew) \
PROC(ImpellerDisplayListBuilderRelease) \
PROC(ImpellerDisplayListBuilderResetTransform) \
PROC(ImpellerDisplayListBuilderRestore) \
PROC(ImpellerDisplayListBuilderRestoreToCount) \
PROC(ImpellerDisplayListBuilderRetain) \
PROC(ImpellerDisplayListBuilderRotate) \
PROC(ImpellerDisplayListBuilderSave) \
PROC(ImpellerDisplayListBuilderSaveLayer) \
PROC(ImpellerDisplayListBuilderScale) \
PROC(ImpellerDisplayListBuilderSetTransform) \
PROC(ImpellerDisplayListBuilderTransform) \
PROC(ImpellerDisplayListBuilderTranslate) \
PROC(ImpellerDisplayListRelease) \
PROC(ImpellerDisplayListRetain) \
PROC(ImpellerGetVersion) \
PROC(ImpellerImageFilterCreateBlurNew) \
PROC(ImpellerImageFilterCreateComposeNew) \
PROC(ImpellerImageFilterCreateDilateNew) \
PROC(ImpellerImageFilterCreateErodeNew) \
PROC(ImpellerImageFilterCreateMatrixNew) \
PROC(ImpellerImageFilterRelease) \
PROC(ImpellerImageFilterRetain) \
PROC(ImpellerMaskFilterCreateBlurNew) \
PROC(ImpellerMaskFilterRelease) \
PROC(ImpellerMaskFilterRetain) \
PROC(ImpellerPaintNew) \
PROC(ImpellerPaintRelease) \
PROC(ImpellerPaintRetain) \
PROC(ImpellerPaintSetBlendMode) \
PROC(ImpellerPaintSetColor) \
PROC(ImpellerPaintSetColorFilter) \
PROC(ImpellerPaintSetColorSource) \
PROC(ImpellerPaintSetDrawStyle) \
PROC(ImpellerPaintSetImageFilter) \
PROC(ImpellerPaintSetMaskFilter) \
PROC(ImpellerPaintSetStrokeCap) \
PROC(ImpellerPaintSetStrokeJoin) \
PROC(ImpellerPaintSetStrokeMiter) \
PROC(ImpellerPaintSetStrokeWidth) \
PROC(ImpellerParagraphBuilderAddText) \
PROC(ImpellerParagraphBuilderBuildParagraphNew) \
PROC(ImpellerParagraphBuilderNew) \
PROC(ImpellerParagraphBuilderPopStyle) \
PROC(ImpellerParagraphBuilderPushStyle) \
PROC(ImpellerParagraphBuilderRelease) \
PROC(ImpellerParagraphBuilderRetain) \
PROC(ImpellerParagraphGetAlphabeticBaseline) \
PROC(ImpellerParagraphGetHeight) \
PROC(ImpellerParagraphGetIdeographicBaseline) \
PROC(ImpellerParagraphGetLineCount) \
PROC(ImpellerParagraphGetLongestLineWidth) \
PROC(ImpellerParagraphGetMaxIntrinsicWidth) \
PROC(ImpellerParagraphGetMaxWidth) \
PROC(ImpellerParagraphGetMinIntrinsicWidth) \
PROC(ImpellerParagraphRelease) \
PROC(ImpellerParagraphRetain) \
PROC(ImpellerParagraphStyleNew) \
PROC(ImpellerParagraphStyleRelease) \
PROC(ImpellerParagraphStyleRetain) \
PROC(ImpellerParagraphStyleSetBackground) \
PROC(ImpellerParagraphStyleSetFontFamily) \
PROC(ImpellerParagraphStyleSetFontSize) \
PROC(ImpellerParagraphStyleSetFontStyle) \
PROC(ImpellerParagraphStyleSetFontWeight) \
PROC(ImpellerParagraphStyleSetForeground) \
PROC(ImpellerParagraphStyleSetHeight) \
PROC(ImpellerParagraphStyleSetLocale) \
PROC(ImpellerParagraphStyleSetMaxLines) \
PROC(ImpellerParagraphStyleSetTextAlignment) \
PROC(ImpellerParagraphStyleSetTextDirection) \
PROC(ImpellerPathBuilderAddArc) \
PROC(ImpellerPathBuilderAddOval) \
PROC(ImpellerPathBuilderAddRect) \
PROC(ImpellerPathBuilderAddRoundedRect) \
PROC(ImpellerPathBuilderClose) \
PROC(ImpellerPathBuilderCopyPathNew) \
PROC(ImpellerPathBuilderCubicCurveTo) \
PROC(ImpellerPathBuilderLineTo) \
PROC(ImpellerPathBuilderMoveTo) \
PROC(ImpellerPathBuilderNew) \
PROC(ImpellerPathBuilderQuadraticCurveTo) \
PROC(ImpellerPathBuilderRelease) \
PROC(ImpellerPathBuilderRetain) \
PROC(ImpellerPathBuilderTakePathNew) \
PROC(ImpellerPathRelease) \
PROC(ImpellerPathRetain) \
PROC(ImpellerSurfaceCreateWrappedFBONew) \
PROC(ImpellerSurfaceCreateWrappedMetalDrawableNew) \
PROC(ImpellerSurfaceDrawDisplayList) \
PROC(ImpellerSurfacePresent) \
PROC(ImpellerSurfaceRelease) \
PROC(ImpellerSurfaceRetain) \
PROC(ImpellerTextureCreateWithContentsNew) \
PROC(ImpellerTextureCreateWithOpenGLTextureHandleNew) \
PROC(ImpellerTextureGetOpenGLHandle) \
PROC(ImpellerTextureRelease) \
PROC(ImpellerTextureRetain) \
PROC(ImpellerTypographyContextNew) \
PROC(ImpellerTypographyContextRegisterFont) \
PROC(ImpellerTypographyContextRelease) \
PROC(ImpellerTypographyContextRetain) \
PROC(ImpellerVulkanSwapchainAcquireNextSurfaceNew) \
PROC(ImpellerVulkanSwapchainCreateNew) \
PROC(ImpellerVulkanSwapchainRelease) \
#define IMPELLER_HPP_EACH_PROC(PROC) \
PROC(ImpellerColorFilterCreateBlendNew) \
PROC(ImpellerColorFilterCreateColorMatrixNew) \
PROC(ImpellerColorFilterRelease) \
PROC(ImpellerColorFilterRetain) \
PROC(ImpellerColorSourceCreateConicalGradientNew) \
PROC(ImpellerColorSourceCreateImageNew) \
PROC(ImpellerColorSourceCreateLinearGradientNew) \
PROC(ImpellerColorSourceCreateRadialGradientNew) \
PROC(ImpellerColorSourceCreateSweepGradientNew) \
PROC(ImpellerColorSourceRelease) \
PROC(ImpellerColorSourceRetain) \
PROC(ImpellerContextCreateMetalNew) \
PROC(ImpellerContextCreateOpenGLESNew) \
PROC(ImpellerContextCreateVulkanNew) \
PROC(ImpellerContextGetVulkanInfo) \
PROC(ImpellerContextRelease) \
PROC(ImpellerContextRetain) \
PROC(ImpellerDisplayListBuilderClipOval) \
PROC(ImpellerDisplayListBuilderClipPath) \
PROC(ImpellerDisplayListBuilderClipRect) \
PROC(ImpellerDisplayListBuilderClipRoundedRect) \
PROC(ImpellerDisplayListBuilderCreateDisplayListNew) \
PROC(ImpellerDisplayListBuilderDrawDashedLine) \
PROC(ImpellerDisplayListBuilderDrawDisplayList) \
PROC(ImpellerDisplayListBuilderDrawLine) \
PROC(ImpellerDisplayListBuilderDrawOval) \
PROC(ImpellerDisplayListBuilderDrawPaint) \
PROC(ImpellerDisplayListBuilderDrawParagraph) \
PROC(ImpellerDisplayListBuilderDrawPath) \
PROC(ImpellerDisplayListBuilderDrawRect) \
PROC(ImpellerDisplayListBuilderDrawRoundedRect) \
PROC(ImpellerDisplayListBuilderDrawRoundedRectDifference) \
PROC(ImpellerDisplayListBuilderDrawShadow) \
PROC(ImpellerDisplayListBuilderDrawTexture) \
PROC(ImpellerDisplayListBuilderDrawTextureRect) \
PROC(ImpellerDisplayListBuilderGetSaveCount) \
PROC(ImpellerDisplayListBuilderGetTransform) \
PROC(ImpellerDisplayListBuilderNew) \
PROC(ImpellerDisplayListBuilderRelease) \
PROC(ImpellerDisplayListBuilderResetTransform) \
PROC(ImpellerDisplayListBuilderRestore) \
PROC(ImpellerDisplayListBuilderRestoreToCount) \
PROC(ImpellerDisplayListBuilderRetain) \
PROC(ImpellerDisplayListBuilderRotate) \
PROC(ImpellerDisplayListBuilderSave) \
PROC(ImpellerDisplayListBuilderSaveLayer) \
PROC(ImpellerDisplayListBuilderScale) \
PROC(ImpellerDisplayListBuilderSetTransform) \
PROC(ImpellerDisplayListBuilderTransform) \
PROC(ImpellerDisplayListBuilderTranslate) \
PROC(ImpellerDisplayListRelease) \
PROC(ImpellerDisplayListRetain) \
PROC(ImpellerGetVersion) \
PROC(ImpellerGlyphInfoGetGraphemeClusterBounds) \
PROC(ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin) \
PROC(ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd) \
PROC(ImpellerGlyphInfoGetTextDirection) \
PROC(ImpellerGlyphInfoIsEllipsis) \
PROC(ImpellerGlyphInfoRelease) \
PROC(ImpellerGlyphInfoRetain) \
PROC(ImpellerImageFilterCreateBlurNew) \
PROC(ImpellerImageFilterCreateComposeNew) \
PROC(ImpellerImageFilterCreateDilateNew) \
PROC(ImpellerImageFilterCreateErodeNew) \
PROC(ImpellerImageFilterCreateMatrixNew) \
PROC(ImpellerImageFilterRelease) \
PROC(ImpellerImageFilterRetain) \
PROC(ImpellerLineMetricsGetAscent) \
PROC(ImpellerLineMetricsGetBaseline) \
PROC(ImpellerLineMetricsGetCodeUnitEndIndex) \
PROC(ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace) \
PROC(ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline) \
PROC(ImpellerLineMetricsGetCodeUnitStartIndex) \
PROC(ImpellerLineMetricsGetDescent) \
PROC(ImpellerLineMetricsGetHeight) \
PROC(ImpellerLineMetricsIsHardbreak) \
PROC(ImpellerLineMetricsGetLeft) \
PROC(ImpellerLineMetricsGetUnscaledAscent) \
PROC(ImpellerLineMetricsGetWidth) \
PROC(ImpellerLineMetricsRelease) \
PROC(ImpellerLineMetricsRetain) \
PROC(ImpellerMaskFilterCreateBlurNew) \
PROC(ImpellerMaskFilterRelease) \
PROC(ImpellerMaskFilterRetain) \
PROC(ImpellerPaintNew) \
PROC(ImpellerPaintRelease) \
PROC(ImpellerPaintRetain) \
PROC(ImpellerPaintSetBlendMode) \
PROC(ImpellerPaintSetColor) \
PROC(ImpellerPaintSetColorFilter) \
PROC(ImpellerPaintSetColorSource) \
PROC(ImpellerPaintSetDrawStyle) \
PROC(ImpellerPaintSetImageFilter) \
PROC(ImpellerPaintSetMaskFilter) \
PROC(ImpellerPaintSetStrokeCap) \
PROC(ImpellerPaintSetStrokeJoin) \
PROC(ImpellerPaintSetStrokeMiter) \
PROC(ImpellerPaintSetStrokeWidth) \
PROC(ImpellerParagraphBuilderAddText) \
PROC(ImpellerParagraphBuilderBuildParagraphNew) \
PROC(ImpellerParagraphBuilderNew) \
PROC(ImpellerParagraphBuilderPopStyle) \
PROC(ImpellerParagraphBuilderPushStyle) \
PROC(ImpellerParagraphBuilderRelease) \
PROC(ImpellerParagraphBuilderRetain) \
PROC(ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew) \
PROC(ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew) \
PROC(ImpellerParagraphGetAlphabeticBaseline) \
PROC(ImpellerParagraphGetHeight) \
PROC(ImpellerParagraphGetIdeographicBaseline) \
PROC(ImpellerParagraphGetLineCount) \
PROC(ImpellerParagraphGetLineMetrics) \
PROC(ImpellerParagraphGetLongestLineWidth) \
PROC(ImpellerParagraphGetMaxIntrinsicWidth) \
PROC(ImpellerParagraphGetMaxWidth) \
PROC(ImpellerParagraphGetMinIntrinsicWidth) \
PROC(ImpellerParagraphGetWordBoundary) \
PROC(ImpellerParagraphRelease) \
PROC(ImpellerParagraphRetain) \
PROC(ImpellerParagraphStyleNew) \
PROC(ImpellerParagraphStyleRelease) \
PROC(ImpellerParagraphStyleRetain) \
PROC(ImpellerParagraphStyleSetBackground) \
PROC(ImpellerParagraphStyleSetFontFamily) \
PROC(ImpellerParagraphStyleSetFontSize) \
PROC(ImpellerParagraphStyleSetFontStyle) \
PROC(ImpellerParagraphStyleSetFontWeight) \
PROC(ImpellerParagraphStyleSetForeground) \
PROC(ImpellerParagraphStyleSetHeight) \
PROC(ImpellerParagraphStyleSetLocale) \
PROC(ImpellerParagraphStyleSetMaxLines) \
PROC(ImpellerParagraphStyleSetTextAlignment) \
PROC(ImpellerParagraphStyleSetTextDirection) \
PROC(ImpellerPathBuilderAddArc) \
PROC(ImpellerPathBuilderAddOval) \
PROC(ImpellerPathBuilderAddRect) \
PROC(ImpellerPathBuilderAddRoundedRect) \
PROC(ImpellerPathBuilderClose) \
PROC(ImpellerPathBuilderCopyPathNew) \
PROC(ImpellerPathBuilderCubicCurveTo) \
PROC(ImpellerPathBuilderLineTo) \
PROC(ImpellerPathBuilderMoveTo) \
PROC(ImpellerPathBuilderNew) \
PROC(ImpellerPathBuilderQuadraticCurveTo) \
PROC(ImpellerPathBuilderRelease) \
PROC(ImpellerPathBuilderRetain) \
PROC(ImpellerPathBuilderTakePathNew) \
PROC(ImpellerPathRelease) \
PROC(ImpellerPathRetain) \
PROC(ImpellerSurfaceCreateWrappedFBONew) \
PROC(ImpellerSurfaceCreateWrappedMetalDrawableNew) \
PROC(ImpellerSurfaceDrawDisplayList) \
PROC(ImpellerSurfacePresent) \
PROC(ImpellerSurfaceRelease) \
PROC(ImpellerSurfaceRetain) \
PROC(ImpellerTextureCreateWithContentsNew) \
PROC(ImpellerTextureCreateWithOpenGLTextureHandleNew) \
PROC(ImpellerTextureGetOpenGLHandle) \
PROC(ImpellerTextureRelease) \
PROC(ImpellerTextureRetain) \
PROC(ImpellerTypographyContextNew) \
PROC(ImpellerTypographyContextRegisterFont) \
PROC(ImpellerTypographyContextRelease) \
PROC(ImpellerTypographyContextRetain) \
PROC(ImpellerVulkanSwapchainAcquireNextSurfaceNew) \
PROC(ImpellerVulkanSwapchainCreateNew) \
PROC(ImpellerVulkanSwapchainRelease) \
PROC(ImpellerVulkanSwapchainRetain)
struct ProcTable {
@ -284,7 +309,9 @@ IMPELLER_HPP_DEFINE_TRAITS(ImpellerColorSource);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerContext);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerDisplayList);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerDisplayListBuilder);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerGlyphInfo);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerImageFilter);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerLineMetrics);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerMaskFilter);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerPaint);
IMPELLER_HPP_DEFINE_TRAITS(ImpellerParagraph);
@ -638,6 +665,149 @@ class MaskFilter final
}
};
//------------------------------------------------------------------------------
/// @see ImpellerGlyphInfo
///
class GlyphInfo final
: public Object<ImpellerGlyphInfo, ImpellerGlyphInfoTraits> {
public:
GlyphInfo(ImpellerGlyphInfo info, AdoptTag tag) : Object(info, tag) {}
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin
///
size_t GetGraphemeClusterCodeUnitRangeBegin() const {
return gGlobalProcTable
.ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeBegin(Get());
}
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd
///
size_t GetGraphemeClusterCodeUnitRangeEnd() const {
return gGlobalProcTable.ImpellerGlyphInfoGetGraphemeClusterCodeUnitRangeEnd(
Get());
}
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetGraphemeClusterBounds
///
ImpellerRect GetGraphemeClusterBounds() const {
return gGlobalProcTable.ImpellerGlyphInfoGetGraphemeClusterBounds(Get());
}
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoIsEllipsis
///
bool IsEllipsis() const {
return gGlobalProcTable.ImpellerGlyphInfoIsEllipsis(Get());
}
//----------------------------------------------------------------------------
/// @see ImpellerGlyphInfoGetTextDirection
///
ImpellerTextDirection GetTextDirection() const {
return gGlobalProcTable.ImpellerGlyphInfoGetTextDirection(Get());
}
};
//------------------------------------------------------------------------------
/// @see ImpellerLineMetrics
///
class LineMetrics final
: public Object<ImpellerLineMetrics, ImpellerLineMetricsTraits> {
public:
LineMetrics(ImpellerLineMetrics metrics, AdoptTag tag)
: Object(metrics, tag) {}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetUnscaledAscent
///
double GetUnscaledAscent(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetUnscaledAscent(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetAscent
///
double GetAscent(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetAscent(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetDescent
///
double GetDescent(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetDescent(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetBaseline
///
double GetBaseline(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetBaseline(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsIsHardbreak
///
bool IsHardbreak(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsIsHardbreak(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetWidth
///
double GetWidth(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetWidth(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetHeight
///
double GetHeight(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetHeight(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetLeft
///
double GetLeft(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetLeft(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitStartIndex
///
size_t GetCodeUnitStartIndex(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetCodeUnitStartIndex(Get(),
line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndex
///
size_t GetCodeUnitEndIndex(size_t line) const {
return gGlobalProcTable.ImpellerLineMetricsGetCodeUnitEndIndex(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace
///
size_t GetCodeUnitEndIndexExcludingWhitespace(size_t line) const {
return gGlobalProcTable
.ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace(Get(), line);
}
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline
///
size_t GetCodeUnitEndIndexIncludingNewline(size_t line) const {
return gGlobalProcTable
.ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline(Get(), line);
}
};
//------------------------------------------------------------------------------
/// @see ImpellerParagraph
///
@ -702,6 +872,47 @@ class Paragraph final
float GetMinIntrinsicWidth() {
return gGlobalProcTable.ImpellerParagraphGetMinIntrinsicWidth(Get());
}
//----------------------------------------------------------------------------
/// @see ImpellerParagraphGetLineMetrics
///
LineMetrics GetLineMetrics() const {
auto metrics = gGlobalProcTable.ImpellerParagraphGetLineMetrics(Get());
gGlobalProcTable.ImpellerLineMetricsRetain(metrics);
return LineMetrics(metrics, AdoptTag::kAdopt);
}
//----------------------------------------------------------------------------
/// @see ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew
///
GlyphInfo GlyphInfoAtCodeUnitIndex(size_t code_unit_index) {
return GlyphInfo(
gGlobalProcTable.ImpellerParagraphCreateGlyphInfoAtCodeUnitIndexNew(
Get(), code_unit_index),
AdoptTag::kAdopt);
}
//----------------------------------------------------------------------------
/// @see ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew
///
GlyphInfo GlyphInfoAtParagraphCoordinates(double x, double y) {
return GlyphInfo(
gGlobalProcTable
.ImpellerParagraphCreateGlyphInfoAtParagraphCoordinatesNew(
Get(), //
x, //
y //
),
AdoptTag::kAdopt);
}
//----------------------------------------------------------------------------
/// @see ImpellerParagraphGetWordBoundary
///
ImpellerRange GetWordBoundary(size_t code_unit_index) {
return gGlobalProcTable.ImpellerParagraphGetWordBoundary(Get(),
code_unit_index);
}
};
//------------------------------------------------------------------------------

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "flutter/fml/native_library.h"
#include "flutter/fml/string_conversion.h"
#include "flutter/testing/testing.h"
#include "impeller/base/allocation.h"
#include "impeller/renderer/backend/gles/context_gles.h"
@ -503,4 +504,82 @@ TEST_P(InteropPlaygroundTest, CanRenderShadows) {
}));
}
TEST_P(InteropPlaygroundTest, CanMeasureText) {
hpp::TypographyContext type_context;
hpp::ParagraphBuilder paragraph_builder(type_context);
hpp::ParagraphStyle paragraph_style;
paragraph_style.SetFontSize(50);
paragraph_builder.PushStyle(paragraph_style);
const std::string text =
"🏁 Can 👨‍👨‍👦‍👦 Measure 🔍 Text\nAnd this is line "
"two.\nWhoa! Three lines. How high does this go?\r\nI stopped counting.";
const auto u16text = fml::Utf8ToUtf16(text);
ASSERT_NE(text.size(), u16text.size());
paragraph_builder.AddText(reinterpret_cast<const uint8_t*>(text.data()),
text.size());
hpp::DisplayListBuilder builder;
// Don't rely on implicit line breaks in this test to make it less brittle to
// different fonts being picked.
hpp::Paragraph paragraph = paragraph_builder.Build(FLT_MAX);
const auto line_count = paragraph.GetLineCount();
ASSERT_EQ(line_count, 4u);
// Line Metrics.
{
auto metrics = paragraph.GetLineMetrics();
ASSERT_GT(metrics.GetAscent(0), 0.0);
ASSERT_GT(metrics.GetUnscaledAscent(0), 0.0);
ASSERT_GT(metrics.GetDescent(0), 0.0);
ASSERT_GT(metrics.GetBaseline(0), 0.0);
ASSERT_TRUE(metrics.IsHardbreak(0));
ASSERT_DOUBLE_EQ(metrics.GetLeft(0), 0.0);
ASSERT_EQ(metrics.GetCodeUnitStartIndex(0), 0u);
ASSERT_EQ(metrics.GetCodeUnitEndIndexIncludingNewline(0),
metrics.GetCodeUnitEndIndex(0) + 1u);
ASSERT_GT(metrics.GetCodeUnitStartIndex(1), 0u);
// Last line should cover the entire range.
ASSERT_EQ(metrics.GetCodeUnitEndIndex(3), u16text.size());
}
// Glyph info by code point.
{
auto glyph = paragraph.GlyphInfoAtCodeUnitIndex(0u);
ASSERT_TRUE(glyph);
ASSERT_EQ(glyph.GetGraphemeClusterCodeUnitRangeBegin(), 0u);
ASSERT_EQ(glyph.GetGraphemeClusterCodeUnitRangeEnd(),
fml::Utf8ToUtf16("🏁").size());
auto bounds = glyph.GetGraphemeClusterBounds();
ASSERT_GT(bounds.width, 0.0);
ASSERT_GT(bounds.height, 0.0);
ASSERT_FALSE(glyph.IsEllipsis());
ASSERT_EQ(glyph.GetTextDirection(), kImpellerTextDirectionLTR);
}
// Glyph info by coordinates.
{
auto glyph = paragraph.GlyphInfoAtParagraphCoordinates(0.0, 0.0);
ASSERT_TRUE(glyph);
ASSERT_EQ(glyph.GetGraphemeClusterCodeUnitRangeEnd(),
fml::Utf8ToUtf16("🏁").size());
}
// Glyph Figure out word boundaries.
{
auto glyph = paragraph.GlyphInfoAtCodeUnitIndex(0u);
ASSERT_TRUE(glyph);
auto range =
paragraph.GetWordBoundary(glyph.GetGraphemeClusterCodeUnitRangeEnd());
ASSERT_GT(range.end, 0u);
}
builder.DrawParagraph(paragraph, ImpellerPoint{100, 100});
auto dl = builder.Build();
ASSERT_TRUE(
OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool {
hpp::Surface window(surface.GetC());
window.Draw(dl);
return true;
}));
}
} // namespace impeller::interop::testing

View File

@ -0,0 +1,76 @@
// 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 "flutter/impeller/toolkit/interop/line_metrics.h"
namespace impeller::interop {
LineMetrics::LineMetrics(const std::vector<txt::LineMetrics>& metrics) {
// There aren't any guarantees (documented or otherwise) that metrics will
// have line numbers that are sorted or contiguous.
for (const auto& metric : metrics) {
metrics_[metric.line_number] = metric;
}
}
LineMetrics::~LineMetrics() = default;
double LineMetrics::GetAscent(size_t line) const {
return GetLine(line).ascent;
}
double LineMetrics::GetUnscaledAscent(size_t line) const {
return GetLine(line).unscaled_ascent;
}
double LineMetrics::GetDescent(size_t line) const {
return GetLine(line).descent;
}
double LineMetrics::GetBaseline(size_t line) const {
return GetLine(line).baseline;
}
bool LineMetrics::IsHardbreak(size_t line) const {
return GetLine(line).hard_break;
}
double LineMetrics::GetWidth(size_t line) const {
return GetLine(line).width;
}
double LineMetrics::GetHeight(size_t line) const {
return GetLine(line).height;
}
double LineMetrics::GetLeft(size_t line) const {
return GetLine(line).left;
}
size_t LineMetrics::GetCodeUnitStartIndex(size_t line) const {
return GetLine(line).start_index;
}
size_t LineMetrics::GetCodeUnitEndIndex(size_t line) const {
return GetLine(line).end_index;
}
size_t LineMetrics::GetCodeUnitEndIndexExcludingWhitespace(size_t line) const {
return GetLine(line).end_excluding_whitespace;
}
size_t LineMetrics::GetCodeUnitEndIndexIncludingNewline(size_t line) const {
return GetLine(line).end_including_newline;
}
const txt::LineMetrics& LineMetrics::GetLine(size_t line) const {
auto found = metrics_.find(line);
if (found != metrics_.end()) {
return found->second;
}
static txt::LineMetrics kDefaultMetrics = {};
return kDefaultMetrics;
}
} // namespace impeller::interop

View File

@ -0,0 +1,104 @@
// 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.
#ifndef FLUTTER_IMPELLER_TOOLKIT_INTEROP_LINE_METRICS_H_
#define FLUTTER_IMPELLER_TOOLKIT_INTEROP_LINE_METRICS_H_
#include <map>
#include "flutter/txt/src/txt/line_metrics.h"
#include "impeller/toolkit/interop/impeller.h"
#include "impeller/toolkit/interop/object.h"
namespace impeller::interop {
//------------------------------------------------------------------------------
/// @brief Internal C++ peer of ImpellerLineMetrics. For detailed
/// documentation, refer to the headerdocs in the public API in
/// impeller.h.
///
/// Accessing metrics of missing lines returns default initialized
/// values.
///
class LineMetrics final
: public Object<LineMetrics,
IMPELLER_INTERNAL_HANDLE_NAME(ImpellerLineMetrics)> {
public:
explicit LineMetrics(const std::vector<txt::LineMetrics>& metrics);
~LineMetrics();
LineMetrics(const LineMetrics&) = delete;
LineMetrics& operator=(const LineMetrics&) = delete;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetAscent.
///
double GetAscent(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetUnscaledAscent.
///
double GetUnscaledAscent(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetDescent.
///
double GetDescent(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetBaseline.
///
double GetBaseline(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsIsHardbreak.
///
bool IsHardbreak(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetWidth.
///
double GetWidth(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetHeight.
///
double GetHeight(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetLeft.
///
double GetLeft(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitStartIndex.
///
size_t GetCodeUnitStartIndex(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndex.
///
size_t GetCodeUnitEndIndex(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndexExcludingWhitespace.
///
size_t GetCodeUnitEndIndexExcludingWhitespace(size_t line) const;
//----------------------------------------------------------------------------
/// @see ImpellerLineMetricsGetCodeUnitEndIndexIncludingNewline.
///
size_t GetCodeUnitEndIndexIncludingNewline(size_t line) const;
private:
std::map<size_t /* line number */, txt::LineMetrics> metrics_;
const txt::LineMetrics& GetLine(size_t line) const;
};
} // namespace impeller::interop
#endif // FLUTTER_IMPELLER_TOOLKIT_INTEROP_LINE_METRICS_H_

View File

@ -47,4 +47,39 @@ const std::unique_ptr<txt::Paragraph>& Paragraph::GetHandle() const {
return paragraph_;
}
ScopedObject<LineMetrics> Paragraph::GetLineMetrics() const {
// Line metrics are expensive to calculate and the recommendation is that
// the metric after each layout must be cached. But interop::Paragraphs are
// immutable. So do the caching on behalf of the caller.
if (lazy_line_metrics_) {
return lazy_line_metrics_;
}
lazy_line_metrics_ = Create<LineMetrics>(paragraph_->GetLineMetrics());
return lazy_line_metrics_;
}
ScopedObject<GlyphInfo> Paragraph::GetGlyphInfoAtCodeUnitIndex(
size_t code_unit_index) const {
skia::textlayout::Paragraph::GlyphInfo info = {};
if (paragraph_->GetGlyphInfoAt(code_unit_index, &info)) {
return Create<GlyphInfo>(info);
}
return nullptr;
}
ScopedObject<GlyphInfo> Paragraph::GetClosestGlyphInfoAtParagraphCoordinates(
double x,
double y) const {
skia::textlayout::Paragraph::GlyphInfo info = {};
if (paragraph_->GetClosestGlyphInfoAtCoordinate(x, y, &info)) {
return Create<GlyphInfo>(info);
}
return nullptr;
}
ImpellerRange Paragraph::GetWordBoundary(size_t code_unit_index) const {
const auto range = paragraph_->GetWordBoundary(code_unit_index);
return ImpellerRange{range.start, range.end};
}
} // namespace impeller::interop

View File

@ -6,11 +6,16 @@
#define FLUTTER_IMPELLER_TOOLKIT_INTEROP_PARAGRAPH_H_
#include "flutter/txt/src/txt/paragraph.h"
#include "impeller/toolkit/interop/glyph_info.h"
#include "impeller/toolkit/interop/impeller.h"
#include "impeller/toolkit/interop/line_metrics.h"
#include "impeller/toolkit/interop/object.h"
namespace impeller::interop {
/**
* An immutable fully laid out paragraph.
*/
class Paragraph final
: public Object<Paragraph,
IMPELLER_INTERNAL_HANDLE_NAME(ImpellerParagraph)> {
@ -41,8 +46,20 @@ class Paragraph final
const std::unique_ptr<txt::Paragraph>& GetHandle() const;
ScopedObject<LineMetrics> GetLineMetrics() const;
ScopedObject<GlyphInfo> GetGlyphInfoAtCodeUnitIndex(
size_t code_unit_index) const;
ScopedObject<GlyphInfo> GetClosestGlyphInfoAtParagraphCoordinates(
double x,
double y) const;
ImpellerRange GetWordBoundary(size_t code_unit_index) const;
private:
std::unique_ptr<txt::Paragraph> paragraph_;
mutable ScopedObject<LineMetrics> lazy_line_metrics_;
};
} // namespace impeller::interop

View File

@ -55,7 +55,7 @@ class LineMetrics {
// are before layout and are the base values we calculate from.
std::map<size_t, RunMetrics> run_metrics;
LineMetrics();
LineMetrics() = default;
LineMetrics(size_t start,
size_t end,