blob: 594e64b797ed2872c43463266cedcf47b442dddf [file] [log] [blame]
// Copyright 2021 Google LLC.
#ifndef Types_DEFINED
#define Types_DEFINED
#include <algorithm>
#include <cstddef>
#include "include/private/SkBitmaskEnum.h"
#include "include/private/SkTo.h"
namespace skia {
namespace text {
enum class TextAlign {
kLeft,
kRight,
kCenter,
kJustify,
kStart,
kEnd,
};
enum class TextDirection {
kRtl,
kLtr,
};
enum class LineBreakType {
kSortLineBreakBefore,
kHardLineBreakBefore,
};
enum CodeUnitFlags : uint32_t {
kNoCodeUnitFlag = 0x000,
kPartOfWhiteSpace = 0x001,
kGraphemeStart = 0x002,
kSoftLineBreakBefore = 0x004,
kHardLineBreakBefore = 0x008,
// This information we get from SkShaper
kGlyphStart = 0x010,
kGlyphClusterStart = 0x020,
kNonExistingFlag = 0x040,
};
typedef size_t TextIndex;
typedef size_t GlyphIndex;
const size_t EMPTY_INDEX = std::numeric_limits<size_t>::max();
template <typename T>
class Range {
public:
Range() : fStart(0), fEnd(0) { }
Range(T start, T end) : fStart(start) , fEnd(end) { }
bool leftToRight() const {
return fEnd >= fStart;
}
void normalize() {
if (!this->leftToRight()) {
std::swap(this->fStart, this->fEnd);
}
}
// For RTL ranges start >= end
int width() const {
return leftToRight() ? SkToInt(fEnd - fStart) : SkToInt(fStart - fEnd);
}
void clean() {
fStart = 0;
fEnd = 0;
}
bool isEmpty() const {
return fEnd == fStart;
}
void merge(Range tail) {
auto ltr1 = this->leftToRight();
auto ltr2 = tail.leftToRight();
this->normalize();
tail.normalize();
SkASSERT(this->fEnd == tail.fStart || this->fStart == tail.fEnd);
this->fStart = std::min(this->fStart, tail.fStart);
this->fEnd = std::max(this->fEnd, tail.fEnd);
// TODO: Merging 2 different directions
if (!ltr1 || !ltr2) {
std::swap(this->fStart, this->fEnd);
std::swap(tail.fStart, tail.fEnd);
}
}
void intersect(Range other) {
auto ltr = this->leftToRight();
this->normalize();
other.normalize();
this->fStart = std::max(this->fStart, other.fStart);
this->fEnd = std::min(this->fEnd, other.fEnd);
if (this->fStart > this->fEnd) {
// There is nothing in the intersection; make it empty
this->fEnd = this->fStart;
} else if (!ltr) {
std::swap(this->fStart, this->fEnd);
}
}
template<typename Visitor>
void iterate(Visitor visitor) {
if (this->leftToRight()) {
for (auto index = this->fStart; index < this->fEnd; ++index) {
visitor(index);
}
} else {
for (auto index = this->fStart; index < this->fEnd; --index) {
visitor(index);
}
}
}
T fStart;
T fEnd;
};
typedef Range<TextIndex> TextRange;
typedef Range<GlyphIndex> GlyphRange;
const Range EMPTY_RANGE = Range(EMPTY_INDEX, EMPTY_INDEX);
} // namespace text
} // namespace skia
namespace sknonstd {
template <> struct is_bitmask_enum<skia::text::CodeUnitFlags> : std::true_type {};
}
#endif