blob: de79933e91eb18b0d314bb82a118072a5192f072 [file] [log] [blame]
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2003, 2006, 2007, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef TextRun_h
#define TextRun_h
#include "platform/PlatformExport.h"
#include "platform/fonts/Glyph.h"
#include "platform/geometry/FloatRect.h"
#include "platform/heap/Heap.h"
#include "platform/text/TabSize.h"
#include "platform/text/TextDirection.h"
#include "platform/text/TextJustify.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/text/StringView.h"
#include "platform/wtf/text/WTFString.h"
#include <SkRefCnt.h>
#include <unicode/utf16.h>
namespace blink {
class PLATFORM_EXPORT TextRun final {
DISALLOW_NEW();
public:
enum ExpansionBehaviorFlags {
kForbidTrailingExpansion = 0 << 0,
kAllowTrailingExpansion = 1 << 0,
kForbidLeadingExpansion = 0 << 1,
kAllowLeadingExpansion = 1 << 1,
};
enum TextCodePath { kAuto = 0, kForceSimple = 1, kForceComplex = 2 };
typedef unsigned ExpansionBehavior;
TextRun(const LChar* c,
unsigned len,
float xpos = 0,
float expansion = 0,
ExpansionBehavior expansion_behavior = kAllowTrailingExpansion |
kForbidLeadingExpansion,
TextDirection direction = TextDirection::kLtr,
bool directional_override = false)
: characters_length_(len),
len_(len),
xpos_(xpos),
horizontal_glyph_stretch_(1),
expansion_(expansion),
expansion_behavior_(expansion_behavior),
is8_bit_(true),
allow_tabs_(false),
direction_(static_cast<unsigned>(direction)),
directional_override_(directional_override),
disable_spacing_(false),
text_justify_(static_cast<unsigned>(TextJustify::kAuto)),
normalize_space_(false),
tab_size_(0) {
data_.characters8 = c;
}
TextRun(const UChar* c,
unsigned len,
float xpos = 0,
float expansion = 0,
ExpansionBehavior expansion_behavior = kAllowTrailingExpansion |
kForbidLeadingExpansion,
TextDirection direction = TextDirection::kLtr,
bool directional_override = false)
: characters_length_(len),
len_(len),
xpos_(xpos),
horizontal_glyph_stretch_(1),
expansion_(expansion),
expansion_behavior_(expansion_behavior),
is8_bit_(false),
allow_tabs_(false),
direction_(static_cast<unsigned>(direction)),
directional_override_(directional_override),
disable_spacing_(false),
text_justify_(static_cast<unsigned>(TextJustify::kAuto)),
normalize_space_(false),
tab_size_(0) {
data_.characters16 = c;
}
TextRun(const StringView& string,
float xpos = 0,
float expansion = 0,
ExpansionBehavior expansion_behavior = kAllowTrailingExpansion |
kForbidLeadingExpansion,
TextDirection direction = TextDirection::kLtr,
bool directional_override = false)
: characters_length_(string.length()),
len_(string.length()),
xpos_(xpos),
horizontal_glyph_stretch_(1),
expansion_(expansion),
expansion_behavior_(expansion_behavior),
allow_tabs_(false),
direction_(static_cast<unsigned>(direction)),
directional_override_(directional_override),
disable_spacing_(false),
text_justify_(static_cast<unsigned>(TextJustify::kAuto)),
normalize_space_(false),
tab_size_(0) {
if (!characters_length_) {
is8_bit_ = true;
data_.characters8 = 0;
} else if (string.Is8Bit()) {
data_.characters8 = string.Characters8();
is8_bit_ = true;
} else {
data_.characters16 = string.Characters16();
is8_bit_ = false;
}
}
TextRun SubRun(unsigned start_offset, unsigned length) const {
DCHECK_LT(start_offset, len_);
TextRun result = *this;
if (Is8Bit()) {
result.SetText(Data8(start_offset), length);
return result;
}
result.SetText(Data16(start_offset), length);
return result;
}
UChar operator[](unsigned i) const {
SECURITY_DCHECK(i < len_);
return Is8Bit() ? data_.characters8[i] : data_.characters16[i];
}
const LChar* Data8(unsigned i) const {
SECURITY_DCHECK(i < len_);
DCHECK(Is8Bit());
return &data_.characters8[i];
}
const UChar* Data16(unsigned i) const {
SECURITY_DCHECK(i < len_);
DCHECK(!Is8Bit());
return &data_.characters16[i];
}
const LChar* Characters8() const {
DCHECK(Is8Bit());
return data_.characters8;
}
const UChar* Characters16() const {
DCHECK(!Is8Bit());
return data_.characters16;
}
UChar32 CodepointAt(unsigned i) const {
SECURITY_DCHECK(i < len_);
if (Is8Bit())
return (*this)[i];
UChar32 codepoint;
U16_GET(Characters16(), 0, i, len_, codepoint);
return codepoint;
}
UChar32 CodepointAtAndNext(unsigned& i) const {
SECURITY_DCHECK(i < len_);
if (Is8Bit())
return (*this)[i++];
UChar32 codepoint;
U16_NEXT(Characters16(), i, len_, codepoint);
return codepoint;
}
const void* Bytes() const { return data_.bytes_; }
bool Is8Bit() const { return is8_bit_; }
unsigned length() const { return len_; }
unsigned CharactersLength() const { return characters_length_; }
bool NormalizeSpace() const { return normalize_space_; }
void SetNormalizeSpace(bool normalize_space) {
normalize_space_ = normalize_space;
}
void SetText(const LChar* c, unsigned len) {
data_.characters8 = c;
len_ = len;
is8_bit_ = true;
}
void SetText(const UChar* c, unsigned len) {
data_.characters16 = c;
len_ = len;
is8_bit_ = false;
}
void SetText(const String&);
void SetCharactersLength(unsigned characters_length) {
characters_length_ = characters_length;
}
void SetExpansionBehavior(ExpansionBehavior behavior) {
expansion_behavior_ = behavior;
}
float HorizontalGlyphStretch() const { return horizontal_glyph_stretch_; }
void SetHorizontalGlyphStretch(float scale) {
horizontal_glyph_stretch_ = scale;
}
bool AllowTabs() const { return allow_tabs_; }
TabSize GetTabSize() const { return tab_size_; }
void SetTabSize(bool, TabSize);
float XPos() const { return xpos_; }
void SetXPos(float x_pos) { xpos_ = x_pos; }
float Expansion() const { return expansion_; }
void SetExpansion(float expansion) { expansion_ = expansion; }
bool AllowsLeadingExpansion() const {
return expansion_behavior_ & kAllowLeadingExpansion;
}
bool AllowsTrailingExpansion() const {
return expansion_behavior_ & kAllowTrailingExpansion;
}
TextDirection Direction() const {
return static_cast<TextDirection>(direction_);
}
bool Rtl() const { return Direction() == TextDirection::kRtl; }
bool Ltr() const { return Direction() == TextDirection::kLtr; }
bool DirectionalOverride() const { return directional_override_; }
bool SpacingDisabled() const { return disable_spacing_; }
void DisableSpacing() { disable_spacing_ = true; }
void SetDirection(TextDirection direction) {
direction_ = static_cast<unsigned>(direction);
}
void SetDirectionalOverride(bool override) {
directional_override_ = override;
}
void SetTextJustify(TextJustify text_justify) {
text_justify_ = static_cast<unsigned>(text_justify);
}
TextJustify GetTextJustify() const {
return static_cast<TextJustify>(text_justify_);
}
// Up-converts to UTF-16 as needed and normalizes spaces and Unicode control
// characters as per the CSS Text Module Level 3 specification.
// https://drafts.csswg.org/css-text-3/#white-space-processing
std::unique_ptr<UChar[]> NormalizedUTF16(unsigned* result_length) const;
private:
union {
const LChar* characters8;
const UChar* characters16;
const void* bytes_;
} data_;
// Marks the end of the characters buffer. Default equals to m_len.
unsigned characters_length_;
unsigned len_;
// m_xpos is the x position relative to the left start of the text line, not
// relative to the left start of the containing block. In the case of right
// alignment or center alignment, left start of the text line is not the same
// as left start of the containing block.
float xpos_;
float horizontal_glyph_stretch_;
float expansion_;
ExpansionBehavior expansion_behavior_ : 2;
unsigned is8_bit_ : 1;
unsigned allow_tabs_ : 1;
unsigned direction_ : 1;
// Was this direction set by an override character.
unsigned directional_override_ : 1;
unsigned disable_spacing_ : 1;
unsigned text_justify_ : 2;
unsigned normalize_space_ : 1;
TabSize tab_size_;
};
inline void TextRun::SetTabSize(bool allow, TabSize size) {
allow_tabs_ = allow;
tab_size_ = size;
}
// Container for parameters needed to paint TextRun.
struct TextRunPaintInfo {
STACK_ALLOCATED();
public:
explicit TextRunPaintInfo(const TextRun& r)
: run(r), from(0), to(r.length()) {}
const TextRun& run;
unsigned from;
unsigned to;
FloatRect bounds;
};
} // namespace blink
#endif