aboutsummaryrefslogtreecommitdiff
path: root/src/platform_win/win_text_layout.cpp
blob: 04b5e928b77024710f862f38ddb9af54a48e5caf (plain)
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
#include "cru/platform/win/win_text_layout.hpp"

#include "cru/platform/win/exception.hpp"
#include "cru/platform/win/graph_manager.hpp"

#include <cassert>
#include <utility>

namespace cru::platform::win {
WinTextLayout::WinTextLayout(GraphManager* graph_manager,
                             std::shared_ptr<WinFontDescriptor> font,
                             std::wstring text) {
  assert(graph_manager);
  assert(font);
  graph_manager_ = graph_manager;
  text_.swap(text);
  font_descriptor_.swap(font);

  ThrowIfFailed(graph_manager_->GetDWriteFactory()->CreateTextLayout(
      text_.c_str(), static_cast<UINT32>(text_.size()),
      font_descriptor_->GetDWriteTextFormat(), max_width_, max_height_,
      &text_layout_));
}

std::wstring WinTextLayout::GetText() { return text_; }

void WinTextLayout::SetText(std::wstring new_text) {
  text_.swap(new_text);
  ThrowIfFailed(graph_manager_->GetDWriteFactory()->CreateTextLayout(
      text_.c_str(), static_cast<UINT32>(text_.size()),
      font_descriptor_->GetDWriteTextFormat(), max_width_, max_height_,
      &text_layout_));
}

std::shared_ptr<FontDescriptor> WinTextLayout::GetFont() {
  return font_descriptor_;
}

void WinTextLayout::SetFont(std::shared_ptr<FontDescriptor> font) {
  auto f = std::dynamic_pointer_cast<WinFontDescriptor>(font);
  assert(f);
  f.swap(font_descriptor_);
  ThrowIfFailed(graph_manager_->GetDWriteFactory()->CreateTextLayout(
      text_.c_str(), static_cast<UINT32>(text_.size()),
      font_descriptor_->GetDWriteTextFormat(), max_width_, max_height_,
      &text_layout_));
}

void WinTextLayout::SetMaxWidth(float max_width) {
  max_width_ = max_width;
  ThrowIfFailed(text_layout_->SetMaxWidth(max_width_));
}

void WinTextLayout::SetMaxHeight(float max_height) {
  max_height_ = max_height;
  ThrowIfFailed(text_layout_->SetMaxHeight(max_height_));
}

ui::Rect WinTextLayout::GetTextBounds() {
  DWRITE_TEXT_METRICS metrics;
  ThrowIfFailed(text_layout_->GetMetrics(&metrics));
  return ui::Rect{metrics.left, metrics.top, metrics.width, metrics.height};
}

std::vector<ui::Rect> WinTextLayout::TextRangeRect(
    const ui::TextRange& text_range) {
  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;
  text_layout_->HitTestTextRange(text_range.position, 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<ui::Rect> result;
  result.reserve(actual_count);

  for (const auto& metrics : hit_test_metrics) {
    result.push_back(ui::Rect{metrics.left, metrics.top,
                              metrics.left + metrics.width,
                              metrics.top + metrics.height});
  }

  return result;
}
}  // namespace cru::platform::win