LTR/RTL iterateThroughClustersInGlyphsOrder simplified

Change-Id: I778039babc51b60f745a0acff91008d285d94b93
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/284926
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Julia Lavrova <jlavrova@google.com>
This commit is contained in:
Julia Lavrova 2020-04-22 14:33:20 -04:00 committed by Skia Commit-Bot
parent 5763b37ffb
commit f4cf893fee
4 changed files with 43 additions and 55 deletions

View File

@ -73,6 +73,16 @@ struct TextBox {
TextBox(SkRect r, TextDirection d) : rect(r), direction(d) {}
};
// -------------------------------------------------------------------
// --- Reversed iterable
template<typename C, typename UnaryFunction>
UnaryFunction directional_for_each(C& c, bool forwards, UnaryFunction f) {
return forwards
? std::for_each(std::begin(c), std::end(c), f)
: std::for_each(std::rbegin(c), std::rend(c), f);
}
const size_t EMPTY_INDEX = std::numeric_limits<size_t>::max();
template <typename T> struct SkRange {
SkRange() : start(), end() {}
@ -99,6 +109,10 @@ template <typename T> struct SkRange {
return std::max(start, other.start) <= std::min(end, other.end);
}
SkRange<size_t> intersection(SkRange<size_t> other) const {
return SkRange<size_t>(std::max(start, other.start), std::min(end, other.end));
}
bool empty() const {
return start == EMPTY_INDEX && end == EMPTY_INDEX;
}

View File

@ -35,28 +35,13 @@ typedef SkRange<CodepointIndex> CodepointRange;
typedef size_t GlyphIndex;
typedef SkRange<GlyphIndex> GlyphRange;
/* This is a part of future LTR/RTL refactoring
// This is a part of a shaped text
// Text range (a, b) can be:
// LTR: [a:b) where a < b
// RTL: (b:a] where a > b
class ShapedSpan {
public:
ShapedSpan(Run* run, TextRange textRange, GlyphRange glyphRange)
: fRun(run)
, fText(textRange)
, fGlyphs(glyphRange) { }
private:
Run* fRun;
TextRange fText;
GlyphRange fGlyphs;
};
*/
struct RunShifts {
RunShifts() { }
RunShifts(size_t count) { fShifts.push_back_n(count, 0.0); }
SkSTArray<128, SkScalar, true> fShifts;
// LTR: [start: end) where start <= end
// RTL: [end: start) where start >= end
class DirText {
DirText(bool dir, size_t s, size_t e) : start(s), end(e) { }
bool isLeftToRight() const { return start <= end; }
size_t start;
size_t end;
};
class InternalLineMetrics;

View File

@ -531,7 +531,7 @@ void TextLine::justify(SkScalar maxWidth) {
SkScalar textLen = 0;
bool whitespacePatch = false;
this->iterateThroughClustersInGlyphsOrder(false, false,
[&whitespacePatches, &textLen, &whitespacePatch](const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost) {
[&whitespacePatches, &textLen, &whitespacePatch](const Cluster* cluster, bool ghost) {
if (cluster->isWhitespaces()) {
if (!whitespacePatch) {
whitespacePatch = true;
@ -555,10 +555,10 @@ void TextLine::justify(SkScalar maxWidth) {
auto ghostShift = maxWidth - this->fAdvance.fX;
// Spread the extra whitespaces
whitespacePatch = false;
this->iterateThroughClustersInGlyphsOrder(false, true, [&](const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost) {
this->iterateThroughClustersInGlyphsOrder(false, true, [&](const Cluster* cluster, bool ghost) {
if (ghost) {
if (leftToRight) {
if (cluster->run()->leftToRight()) {
shiftCluster(cluster, ghostShift, ghostShift);
}
return true;
@ -632,7 +632,7 @@ void TextLine::createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool)
};
iterateThroughClustersInGlyphsOrder(
true, false, [&](const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost) {
true, false, [&](const Cluster* cluster, bool ghost) {
return !attachEllipsis(cluster);
});
@ -779,39 +779,29 @@ TextLine::ClipContext TextLine::measureTextInsideOneRun(TextRange textRange,
return result;
}
void TextLine::iterateThroughClustersInGlyphsOrder(bool reverse,
void TextLine::iterateThroughClustersInGlyphsOrder(bool reversed,
bool includeGhosts,
const ClustersVisitor& visitor) const {
// Walk through the clusters in the logical order (or reverse)
for (size_t r = 0; r != fRunsInVisualOrder.size(); ++r) {
auto& runIndex = fRunsInVisualOrder[reverse ? fRunsInVisualOrder.size() - r - 1 : r];
auto run = this->fMaster->runs().begin() + runIndex;
auto start = std::max(run->clusterRange().start, fClusterRange.start);
auto end = std::min(run->clusterRange().end, fClusterRange.end);
auto ghosts = std::min(run->clusterRange().end, fGhostClusterRange.end);
SkSpan<const size_t> runs(fRunsInVisualOrder.data(), fRunsInVisualOrder.size());
directional_for_each(runs, reversed, [&](decltype(runs[0]) r) {
auto run = this->fMaster->run(r);
auto trimmedRange = fClusterRange.intersection(run.clusterRange());
auto trailedRange = fGhostClusterRange.intersection(run.clusterRange());
SkASSERT(trimmedRange.start == trailedRange.start);
if (run->leftToRight() != reverse) {
for (auto index = start; index < ghosts; ++index) {
if (index >= end && !includeGhosts) {
break;
}
const auto& cluster = &fMaster->cluster(index);
if (!visitor(cluster, index, run->leftToRight(), index >= end)) {
return;
}
auto trailed = fMaster->clusters(trailedRange);
auto trimmed = fMaster->clusters(trimmedRange);
directional_for_each(trailed, reversed != run.leftToRight(), [&](Cluster& cluster) {
bool ghost = &cluster >= trimmed.end();
if (!includeGhosts && ghost) {
return;
}
} else {
for (auto index = ghosts; index > start; --index) {
if (index > end && !includeGhosts) {
continue;
}
const auto& cluster = &fMaster->cluster(index - 1);
if (!visitor(cluster, index - 1, run->leftToRight(), index > end)) {
return;
}
if (!visitor(&cluster, ghost)) {
return;
}
}
}
});
});
}
SkScalar TextLine::iterateThroughSingleRunByStyles(const Run* run,

View File

@ -68,8 +68,7 @@ public:
SkScalar iterateThroughSingleRunByStyles(const Run* run, SkScalar runOffset, TextRange textRange,
StyleType styleType, const RunStyleVisitor& visitor) const;
using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost)>;
using ClustersVisitor = std::function<bool(const Cluster* cluster, bool ghost)>;
void iterateThroughClustersInGlyphsOrder(bool reverse, bool includeGhosts, const ClustersVisitor& visitor) const;
void format(TextAlign effectiveAlign, SkScalar maxWidth);