1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#include "cru/win/graphics/direct/TextLayout.hpp"
#include "cru/common/Logger.hpp"
#include "cru/platform/Check.hpp"
#include "cru/win/graphics/direct/Exception.hpp"
#include "cru/win/graphics/direct/Factory.hpp"
#include "cru/win/graphics/direct/Font.hpp"
#include <utility>
namespace cru::platform::graphics::win::direct {
DWriteTextLayout::DWriteTextLayout(DirectGraphFactory* factory,
std::shared_ptr<IFont> font,
std::u16string text)
: DirectGraphResource(factory), text_(std::move(text)) {
Expects(font);
font_ = CheckPlatform<DWriteFont>(font, GetPlatformId());
ThrowIfFailed(factory->GetDWriteFactory()->CreateTextLayout(
reinterpret_cast<const wchar_t*>(text_.c_str()),
static_cast<UINT32>(text_.size()), font_->GetComInterface(), max_width_,
max_height_, &text_layout_));
}
DWriteTextLayout::~DWriteTextLayout() = default;
std::u16string DWriteTextLayout::GetText() { return text_; }
std::u16string_view DWriteTextLayout::GetTextView() { return text_; }
void DWriteTextLayout::SetText(std::u16string new_text) {
text_.swap(new_text);
ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout(
reinterpret_cast<const wchar_t*>(text_.c_str()),
static_cast<UINT32>(text_.size()), font_->GetComInterface(), max_width_,
max_height_, &text_layout_));
}
std::shared_ptr<IFont> DWriteTextLayout::GetFont() {
return std::dynamic_pointer_cast<IFont>(font_);
}
void DWriteTextLayout::SetFont(std::shared_ptr<IFont> font) {
font_ = CheckPlatform<DWriteFont>(font, GetPlatformId());
ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout(
reinterpret_cast<const wchar_t*>(text_.c_str()),
static_cast<UINT32>(text_.size()), font_->GetComInterface(), max_width_,
max_height_, &text_layout_));
}
void DWriteTextLayout::SetMaxWidth(float max_width) {
max_width_ = max_width;
ThrowIfFailed(text_layout_->SetMaxWidth(max_width_));
}
void DWriteTextLayout::SetMaxHeight(float max_height) {
max_height_ = max_height;
ThrowIfFailed(text_layout_->SetMaxHeight(max_height_));
}
Rect DWriteTextLayout::GetTextBounds(bool includingTrailingSpace) {
DWRITE_TEXT_METRICS metrics;
ThrowIfFailed(text_layout_->GetMetrics(&metrics));
return Rect{metrics.left, metrics.top,
includingTrailingSpace ? metrics.widthIncludingTrailingWhitespace
: metrics.width,
metrics.height};
}
std::vector<Rect> DWriteTextLayout::TextRangeRect(
const TextRange& text_range_arg) {
if (text_range_arg.count == 0) {
return {};
}
const auto text_range = text_range_arg.Normalize();
DWRITE_TEXT_METRICS text_metrics;
ThrowIfFailed(text_layout_->GetMetrics(&text_metrics));
const auto metrics_count =
text_metrics.lineCount * text_metrics.maxBidiReorderingDepth;
std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count);
UINT32 actual_count;
ThrowIfFailed(text_layout_->HitTestTextRange(
static_cast<UINT32>(text_range.position),
static_cast<UINT32>(text_range.count), 0, 0, hit_test_metrics.data(),
metrics_count, &actual_count));
hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count,
hit_test_metrics.cend());
std::vector<Rect> result;
result.reserve(actual_count);
for (const auto& metrics : hit_test_metrics) {
result.push_back(
Rect{metrics.left, metrics.top, metrics.width, metrics.height});
}
return result;
}
Point DWriteTextLayout::TextSinglePoint(Index position, bool trailing) {
DWRITE_HIT_TEST_METRICS metrics;
FLOAT left;
FLOAT top;
ThrowIfFailed(text_layout_->HitTestTextPosition(static_cast<UINT32>(position),
static_cast<BOOL>(trailing),
&left, &top, &metrics));
return Point{left, top};
}
TextHitTestResult DWriteTextLayout::HitTest(const Point& point) {
BOOL trailing;
BOOL inside;
DWRITE_HIT_TEST_METRICS metrics;
ThrowIfFailed(text_layout_->HitTestPoint(point.x, point.y, &trailing, &inside,
&metrics));
TextHitTestResult result;
result.position = metrics.textPosition;
result.trailing = trailing != 0;
result.insideText = inside != 0;
return result;
}
} // namespace cru::platform::graphics::win::direct
|