aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-10-31 22:53:11 +0800
committercrupest <crupest@outlook.com>2021-10-31 22:53:11 +0800
commit1dca2841da6f024f613d6dc16de456d5035f8fce (patch)
tree37ca6290afbe5900df2eb4a09e30024257d55316
parente68e0d9a5130e8bc0b634572b7fd44b9bfc0f8ef (diff)
downloadcru-1dca2841da6f024f613d6dc16de456d5035f8fce.tar.gz
cru-1dca2841da6f024f613d6dc16de456d5035f8fce.tar.bz2
cru-1dca2841da6f024f613d6dc16de456d5035f8fce.zip
...
-rw-r--r--demos/input_method/main.cpp7
-rw-r--r--include/cru/osx/graphics/quartz/TextLayout.hpp10
-rw-r--r--include/cru/platform/GraphicsBase.hpp13
-rw-r--r--include/cru/platform/Matrix.hpp9
-rw-r--r--include/cru/platform/graphics/TextLayout.hpp3
-rw-r--r--include/cru/ui/render/TextRenderObject.hpp2
-rw-r--r--src/osx/graphics/quartz/Painter.cpp11
-rw-r--r--src/osx/graphics/quartz/TextLayout.cpp171
-rw-r--r--src/osx/gui/Window.mm15
-rw-r--r--src/ui/Helper.hpp1
-rw-r--r--src/ui/render/TextRenderObject.cpp6
11 files changed, 152 insertions, 96 deletions
diff --git a/demos/input_method/main.cpp b/demos/input_method/main.cpp
index 67743239..913f0ae2 100644
--- a/demos/input_method/main.cpp
+++ b/demos/input_method/main.cpp
@@ -94,9 +94,10 @@ int main() {
const auto cursor_lefttop =
text_layout->TextSinglePoint(cursor_pos, false);
- painter->FillRectangle(Rect{cursor_lefttop.x, cursor_lefttop.y + anchor_y,
- 3, font->GetFontSize()},
- brush.get());
+ painter->FillRectangle(
+ Rect{cursor_lefttop.left, cursor_lefttop.top + anchor_y, 3,
+ cursor_lefttop.height},
+ brush.get());
}
});
diff --git a/include/cru/osx/graphics/quartz/TextLayout.hpp b/include/cru/osx/graphics/quartz/TextLayout.hpp
index 95e3d1be..35bcc32d 100644
--- a/include/cru/osx/graphics/quartz/TextLayout.hpp
+++ b/include/cru/osx/graphics/quartz/TextLayout.hpp
@@ -30,19 +30,25 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout {
Rect GetTextBounds(bool includingTrailingSpace = false) override;
std::vector<Rect> TextRangeRect(const TextRange& text_range) override;
- Point TextSinglePoint(Index position, bool trailing) override;
+ Rect TextSinglePoint(Index position, bool trailing) override;
TextHitTestResult HitTest(const Point& point) override;
CTFrameRef GetCTFrameRef() const { return ct_frame_; }
CTFrameRef CreateFrameWithColor(const Color& color);
+ Matrix GetTransform() { return transform_; }
+
String GetDebugString() override;
private:
void ReleaseResource();
void RecreateFrame();
+ Rect DoGetTextBounds(bool includingTrailingSpace = false);
+ std::vector<Rect> DoTextRangeRect(const TextRange& text_range);
+ Rect DoTextSinglePoint(Index position, bool trailing);
+
private:
float max_width_;
float max_height_;
@@ -58,5 +64,7 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout {
int line_count_;
std::vector<CGPoint> line_origins_;
std::vector<CTLineRef> lines_;
+
+ Matrix transform_;
};
} // namespace cru::platform::graphics::osx::quartz
diff --git a/include/cru/platform/GraphicsBase.hpp b/include/cru/platform/GraphicsBase.hpp
index aee718a1..73b41bb5 100644
--- a/include/cru/platform/GraphicsBase.hpp
+++ b/include/cru/platform/GraphicsBase.hpp
@@ -206,6 +206,19 @@ struct Rect final {
point.y < GetBottom();
}
+ constexpr Rect Normalize() const {
+ Rect result = *this;
+ if (result.width < 0) {
+ result.left += result.width;
+ result.width = -result.width;
+ }
+ if (result.height < 0) {
+ result.top += result.height;
+ result.height = -result.height;
+ }
+ return result;
+ }
+
float left = 0.0f;
float top = 0.0f;
float width = 0.0f;
diff --git a/include/cru/platform/Matrix.hpp b/include/cru/platform/Matrix.hpp
index 72459b79..47917d47 100644
--- a/include/cru/platform/Matrix.hpp
+++ b/include/cru/platform/Matrix.hpp
@@ -43,6 +43,15 @@ struct Matrix {
point.x * m12 + point.y * m22 + m32};
}
+ Rect TransformRect(const Rect& rect, bool normalize = true) const {
+ Point lefttop = TransformPoint(rect.GetLeftTop()),
+ rightbottom = TransformPoint(rect.GetRightBottom());
+ auto result =
+ Rect::FromVertices(lefttop.x, lefttop.y, rightbottom.x, rightbottom.y);
+ if (normalize) result = result.Normalize();
+ return result;
+ }
+
static Matrix Identity() {
return Matrix{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
}
diff --git a/include/cru/platform/graphics/TextLayout.hpp b/include/cru/platform/graphics/TextLayout.hpp
index ec3c2d96..5f98696d 100644
--- a/include/cru/platform/graphics/TextLayout.hpp
+++ b/include/cru/platform/graphics/TextLayout.hpp
@@ -17,7 +17,8 @@ struct ITextLayout : virtual IGraphicsResource {
virtual Rect GetTextBounds(bool includingTrailingSpace = false) = 0;
virtual std::vector<Rect> TextRangeRect(const TextRange& text_range) = 0;
- virtual Point TextSinglePoint(Index position, bool trailing) = 0;
+ // Width is always 0, height is line height.
+ virtual Rect TextSinglePoint(Index position, bool trailing) = 0;
virtual TextHitTestResult HitTest(const Point& point) = 0;
};
} // namespace cru::platform::graphics
diff --git a/include/cru/ui/render/TextRenderObject.hpp b/include/cru/ui/render/TextRenderObject.hpp
index ef39b7a6..68d2d0ce 100644
--- a/include/cru/ui/render/TextRenderObject.hpp
+++ b/include/cru/ui/render/TextRenderObject.hpp
@@ -43,7 +43,7 @@ class TextRenderObject : public RenderObject {
void SetFont(std::shared_ptr<platform::graphics::IFont> font);
std::vector<Rect> TextRangeRect(const TextRange& text_range);
- Point TextSinglePoint(gsl::index position, bool trailing);
+ Rect TextSinglePoint(gsl::index position, bool trailing);
platform::graphics::TextHitTestResult TextHitTest(const Point& point);
std::optional<TextRange> GetSelectionRange() const {
diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp
index 5657e048..798e1256 100644
--- a/src/osx/graphics/quartz/Painter.cpp
+++ b/src/osx/graphics/quartz/Painter.cpp
@@ -158,16 +158,7 @@ void QuartzCGContextPainter::DrawText(const Point& offset,
color = colors::black;
}
- auto bounds = tl->GetTextBounds();
-
- bounds.width += bounds.left;
- bounds.height += bounds.top;
- bounds.left = bounds.top = 0;
-
- Matrix transform =
- Matrix::Translation(-bounds.width / 2, -bounds.height / 2) *
- Matrix::Scale(1, -1) *
- Matrix::Translation(bounds.width / 2, bounds.height / 2);
+ Matrix transform = tl->GetTransform();
CGContextSaveGState(cg_context_);
diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp
index 5145f9f9..d30c386f 100644
--- a/src/osx/graphics/quartz/TextLayout.cpp
+++ b/src/osx/graphics/quartz/TextLayout.cpp
@@ -72,83 +72,21 @@ void OsxCTTextLayout::SetMaxHeight(float max_height) {
}
Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) {
- float left = std::numeric_limits<float>::max();
- float top = std::numeric_limits<float>::max();
- float right = 0;
- float bottom = 0;
-
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- const auto& line_origin = line_origins_[i];
-
- CGRect line_rect = CTLineGetImageBounds(line, nullptr);
- if (includingTrailingSpace) {
- float trailingWidth = CTLineGetTrailingWhitespaceWidth(line);
- line_rect.size.width += trailingWidth;
- }
-
- line_rect.origin.x += line_origin.x;
- line_rect.origin.y += line_origin.y;
-
- left = std::min<float>(line_rect.origin.x, left);
- top = std::min<float>(line_rect.origin.y, top);
- right = std::max<float>(line_rect.origin.x + line_rect.size.width, right);
- bottom =
- std::max<float>(line_rect.origin.y + line_rect.size.height, bottom);
- }
-
- return Rect::FromVertices(left, top, right, bottom);
+ return transform_.TransformRect(DoGetTextBounds(includingTrailingSpace));
}
std::vector<Rect> OsxCTTextLayout::TextRangeRect(const TextRange& text_range) {
- const auto r = text_.RangeFromCodeUnitToCodePoint(text_range).Normalize();
+ std::vector<Rect> results = DoTextRangeRect(text_range);
- std::vector<Rect> results;
-
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- const auto& line_origin = line_origins_[i];
-
- Range range = Convert(CTLineGetStringRange(line));
- range = range.CoerceInto(r.GetStart(), r.GetEnd());
-
- if (range.count) {
- auto line_rect = CTLineGetImageBounds(line, nullptr);
- line_rect.origin.x += line_origin.x;
- line_rect.origin.y += line_origin.y;
- float start_offset =
- CTLineGetOffsetForStringIndex(line, range.GetStart(), nullptr);
- float end_offset =
- CTLineGetOffsetForStringIndex(line, range.GetEnd(), nullptr);
- line_rect.origin.x += start_offset;
- line_rect.size.width = end_offset - start_offset;
- results.push_back(Convert(line_rect));
- }
+ for (auto& rect : results) {
+ rect = transform_.TransformRect(rect);
}
return results;
}
-Point OsxCTTextLayout::TextSinglePoint(Index position, bool trailing) {
- position = text_.IndexFromCodeUnitToCodePoint(position);
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- const auto& line_origin = line_origins_[i];
-
- Range range = Convert(CTLineGetStringRange(line));
- if (range.GetStart() <= position && position < range.GetEnd()) {
- auto offset = CTLineGetOffsetForStringIndex(line, position, nullptr);
- return Point(line_origin.x + offset, line_origin.y);
- } else if (position == range.GetEnd()) {
- return Point(
- line_origin.x + CTLineGetImageBounds(line, nullptr).size.width,
- line_origin.y);
- }
- }
-
- if (lines_.empty()) return Point{};
-
- return Convert(CTLineGetImageBounds(lines_.back(), nullptr)).GetRightTop();
+Rect OsxCTTextLayout::TextSinglePoint(Index position, bool trailing) {
+ return transform_.TransformRect(DoTextSinglePoint(position, trailing));
}
TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) {
@@ -213,6 +151,13 @@ void OsxCTTextLayout::RecreateFrame() {
for (int i = 0; i < line_count_; i++) {
lines_[i] = static_cast<CTLineRef>(CFArrayGetValueAtIndex(lines, i));
}
+
+ auto bounds = DoGetTextBounds(false);
+
+ transform_ =
+ Matrix::Translation(-bounds.GetRight() / 2, -bounds.GetBottom() / 2) *
+ Matrix::Scale(1, -1) *
+ Matrix::Translation(bounds.GetRight() / 2, bounds.GetBottom() / 2);
}
CTFrameRef OsxCTTextLayout::CreateFrameWithColor(const Color& color) {
@@ -243,4 +188,94 @@ String OsxCTTextLayout::GetDebugString() {
max_height_);
}
+Rect OsxCTTextLayout::DoGetTextBounds(bool includingTrailingSpace) {
+ if (text_.empty()) return Rect{};
+
+ float left = std::numeric_limits<float>::max();
+ float top = std::numeric_limits<float>::max();
+ float right = 0;
+ float bottom = 0;
+
+ for (int i = 0; i < line_count_; i++) {
+ auto line = lines_[i];
+ const auto& line_origin = line_origins_[i];
+
+ CGRect line_rect = CTLineGetImageBounds(line, nullptr);
+ if (includingTrailingSpace) {
+ float trailingWidth = CTLineGetTrailingWhitespaceWidth(line);
+ line_rect.size.width += trailingWidth;
+ }
+
+ line_rect.origin.x += line_origin.x;
+ line_rect.origin.y += line_origin.y;
+
+ left = std::min<float>(line_rect.origin.x, left);
+ top = std::min<float>(line_rect.origin.y, top);
+ right = std::max<float>(line_rect.origin.x + line_rect.size.width, right);
+ bottom =
+ std::max<float>(line_rect.origin.y + line_rect.size.height, bottom);
+ }
+
+ return Rect::FromVertices(left, top, right, bottom);
+}
+
+std::vector<Rect> OsxCTTextLayout::DoTextRangeRect(
+ const TextRange& text_range) {
+ const auto r = text_.RangeFromCodeUnitToCodePoint(text_range).Normalize();
+
+ std::vector<Rect> results;
+
+ for (int i = 0; i < line_count_; i++) {
+ auto line = lines_[i];
+ const auto& line_origin = line_origins_[i];
+
+ Range range = Convert(CTLineGetStringRange(line));
+ range = range.CoerceInto(r.GetStart(), r.GetEnd());
+
+ if (range.count) {
+ auto line_rect = CTLineGetImageBounds(line, nullptr);
+ line_rect.origin.x += line_origin.x;
+ line_rect.origin.y += line_origin.y;
+ float start_offset =
+ CTLineGetOffsetForStringIndex(line, range.GetStart(), nullptr);
+ float end_offset =
+ CTLineGetOffsetForStringIndex(line, range.GetEnd(), nullptr);
+ line_rect.origin.x += start_offset;
+ line_rect.size.width = end_offset - start_offset;
+ results.push_back(Convert(line_rect));
+ }
+ }
+
+ return results;
+}
+
+Rect OsxCTTextLayout::DoTextSinglePoint(Index position, bool trailing) {
+ if (lines_.empty()) return Rect{0, 0, 0, font_->GetFontSize()};
+
+ position = text_.IndexFromCodeUnitToCodePoint(position);
+ for (int i = 0; i < line_count_; i++) {
+ auto line = lines_[i];
+ const auto& line_origin = line_origins_[i];
+
+ auto rect = Convert(CTLineGetImageBounds(line, nullptr));
+ rect.left += line_origin.x;
+ rect.top += line_origin.y;
+
+ Range range = Convert(CTLineGetStringRange(line));
+ if (range.GetStart() <= position && position < range.GetEnd()) {
+ auto offset = CTLineGetOffsetForStringIndex(line, position, nullptr);
+ return Rect(rect.left + offset, rect.top, 0, rect.height);
+ } else if (position == range.GetEnd()) {
+ return Rect(rect.GetRight(), rect.top, 0, rect.height);
+ }
+ }
+
+ // TODO: Complete logic here.
+
+ auto rect = Convert(CTLineGetImageBounds(lines_.back(), nullptr));
+ rect.left = rect.GetRight();
+ rect.width = 0;
+ return rect;
+}
+
} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm
index 9a71d271..356c6be6 100644
--- a/src/osx/gui/Window.mm
+++ b/src/osx/gui/Window.mm
@@ -27,7 +27,6 @@
#include <Foundation/NSAttributedString.h>
#include <Foundation/NSString.h>
-#include <gsl/gsl_assert>
#include <limits>
#include <memory>
#include <unordered_set>
@@ -496,11 +495,11 @@ const std::unordered_set<KeyCode> bypass_codes{
auto ss = Convert(s);
- cru::log::TagDebug(u"CruView",
- u"Received setMarkedText string: {}, selected range: ({}, {}), "
- u"replacement range: ({}, {}).",
- ss, selectedRange.location, selectedRange.length, replacementRange.location,
- replacementRange.length);
+ // cru::log::TagDebug(u"CruView",
+ // u"Received setMarkedText string: {}, selected range: ({}, {}), "
+ // u"replacement range: ({}, {}).",
+ // ss, selectedRange.location, selectedRange.length, replacementRange.location,
+ // replacementRange.length);
if (_input_context_text == nil) {
_input_context_text = [[NSMutableAttributedString alloc] init];
@@ -557,8 +556,8 @@ const std::unordered_set<KeyCode> bypass_codes{
_input_context_p->SetCompositionText(cru::platform::gui::CompositionText());
cru::String ss = Convert(s);
- cru::log::TagDebug(u"CruView", u"Finish composition: {}, replacement range: ({}, {})", ss,
- replacementRange.location, replacementRange.length);
+ // cru::log::TagDebug(u"CruView", u"Finish composition: {}, replacement range: ({}, {})", ss,
+ // replacementRange.location, replacementRange.length);
_input_context_p->RaiseCompositionEvent();
_input_context_p->RaiseCompositionEndEvent();
diff --git a/src/ui/Helper.hpp b/src/ui/Helper.hpp
index 27f1d7e6..23d24b66 100644
--- a/src/ui/Helper.hpp
+++ b/src/ui/Helper.hpp
@@ -6,7 +6,6 @@ namespace graphics {
struct IGraphicsFactory;
}
namespace native {
-struct ICursor;
struct IUiApplication;
} // namespace native
} // namespace cru::platform
diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp
index 189c5532..df95b5f4 100644
--- a/src/ui/render/TextRenderObject.cpp
+++ b/src/ui/render/TextRenderObject.cpp
@@ -62,7 +62,7 @@ std::vector<Rect> TextRenderObject::TextRangeRect(const TextRange& text_range) {
return text_layout_->TextRangeRect(text_range);
}
-Point TextRenderObject::TextSinglePoint(gsl::index position, bool trailing) {
+Rect TextRenderObject::TextSinglePoint(gsl::index position, bool trailing) {
return text_layout_->TextSinglePoint(position, trailing);
}
@@ -134,8 +134,8 @@ Rect TextRenderObject::GetCaretRectInContent() {
const auto font_height = this->font_->GetFontSize();
const auto caret_width = this->caret_width_;
- auto rect = Rect{caret_top_center.x - caret_width / 2.0f, caret_top_center.y,
- caret_width, font_height};
+ auto rect = Rect{caret_top_center.left - caret_width / 2.0f,
+ caret_top_center.top, caret_width, caret_top_center.height};
return rect;
}