aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-10-19 22:33:01 +0800
committercrupest <crupest@outlook.com>2021-10-19 22:33:01 +0800
commitfd2e84640b2be52f97f48d818d26fc1289a50c7a (patch)
treeab94a27fae4b4bb47a6124a478b20c82a1393b9b
parent44f24f8ece48fd4acc2e8d5f5a052cbc1981768c (diff)
downloadcru-fd2e84640b2be52f97f48d818d26fc1289a50c7a.tar.gz
cru-fd2e84640b2be52f97f48d818d26fc1289a50c7a.tar.bz2
cru-fd2e84640b2be52f97f48d818d26fc1289a50c7a.zip
...
-rw-r--r--include/cru/common/Logger.hpp16
-rw-r--r--include/cru/osx/graphics/quartz/Painter.hpp20
-rw-r--r--include/cru/osx/graphics/quartz/TextLayout.hpp2
-rw-r--r--include/cru/platform/Color.hpp5
-rw-r--r--src/common/Logger.cpp29
-rw-r--r--src/osx/graphics/quartz/Painter.cpp49
-rw-r--r--src/osx/gui/UiApplication.mm4
-rw-r--r--src/osx/gui/Window.mm92
8 files changed, 183 insertions, 34 deletions
diff --git a/include/cru/common/Logger.hpp b/include/cru/common/Logger.hpp
index 3dabeb91..7d43fc5a 100644
--- a/include/cru/common/Logger.hpp
+++ b/include/cru/common/Logger.hpp
@@ -94,4 +94,20 @@ void TagError(StringView tag, TArgs&&... args) {
Logger::GetInstance()->Log(LogLevel::Error, tag,
Format(std::forward<TArgs>(args)...));
}
+
+class StdioLogSource : public Object, public virtual ILogSource {
+ public:
+ explicit StdioLogSource(bool use_lock = false);
+
+ CRU_DELETE_COPY(StdioLogSource)
+ CRU_DELETE_MOVE(StdioLogSource)
+
+ ~StdioLogSource() override;
+
+ public:
+ void Write(LogLevel level, StringView s) override;
+
+ private:
+ bool use_lock_;
+};
} // namespace cru::log
diff --git a/include/cru/osx/graphics/quartz/Painter.hpp b/include/cru/osx/graphics/quartz/Painter.hpp
index 8d693d8b..ea64c3d5 100644
--- a/include/cru/osx/graphics/quartz/Painter.hpp
+++ b/include/cru/osx/graphics/quartz/Painter.hpp
@@ -6,17 +6,19 @@
#include <CoreGraphics/CoreGraphics.h>
+#include <functional>
+
namespace cru::platform::graphics::osx::quartz {
class QuartzCGContextPainter : public OsxQuartzResource,
public virtual IPainter {
+ CRU_DEFINE_CLASS_LOG_TAG(
+ u"cru::platform::graphics::osx::quartz::QuartzCGContextPainter")
+
public:
- explicit QuartzCGContextPainter(IGraphicsFactory* graphics_factory,
- CGContextRef cg_context, bool auto_release,
- const Size& size)
- : OsxQuartzResource(graphics_factory),
- cg_context_(cg_context),
- auto_release_(auto_release),
- size_(size) {}
+ explicit QuartzCGContextPainter(
+ IGraphicsFactory* graphics_factory, CGContextRef cg_context,
+ bool auto_release, const Size& size,
+ std::function<void(QuartzCGContextPainter*)> on_end_draw);
CRU_DELETE_COPY(QuartzCGContextPainter)
CRU_DELETE_MOVE(QuartzCGContextPainter)
@@ -48,6 +50,8 @@ class QuartzCGContextPainter : public OsxQuartzResource,
void EndDraw() override;
private:
+ void DoEndDraw();
+
void Validate();
private:
@@ -56,5 +60,7 @@ class QuartzCGContextPainter : public OsxQuartzResource,
bool auto_release_;
Size size_;
+
+ std::function<void(QuartzCGContextPainter*)> on_end_draw_;
};
} // namespace cru::platform::graphics::osx::quartz
diff --git a/include/cru/osx/graphics/quartz/TextLayout.hpp b/include/cru/osx/graphics/quartz/TextLayout.hpp
index 4d23a76e..dd170142 100644
--- a/include/cru/osx/graphics/quartz/TextLayout.hpp
+++ b/include/cru/osx/graphics/quartz/TextLayout.hpp
@@ -33,6 +33,8 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout {
Point TextSinglePoint(Index position, bool trailing) override;
TextHitTestResult HitTest(const Point& point) override;
+ CTFrameRef GetCTFrameRef() const { return ct_frame_; }
+
private:
void RecreateFrame();
diff --git a/include/cru/platform/Color.hpp b/include/cru/platform/Color.hpp
index 3a72aa65..f60ab692 100644
--- a/include/cru/platform/Color.hpp
+++ b/include/cru/platform/Color.hpp
@@ -257,4 +257,9 @@ extern const std::unordered_map<StringView, Color> predefined_name_color_map;
} // namespace details
std::optional<Color> GetPredefinedColorByName(StringView name);
+
+inline String ToString(const Color& color) {
+ return cru::Format(u"rgba({}, {}, {}, {})", color.red, color.green,
+ color.blue, color.alpha);
+}
} // namespace cru::platform
diff --git a/src/common/Logger.cpp b/src/common/Logger.cpp
index 6ba5d578..3034c0ad 100644
--- a/src/common/Logger.cpp
+++ b/src/common/Logger.cpp
@@ -3,7 +3,9 @@
#include <array>
#include <cstdlib>
#include <ctime>
+#include <iostream>
#include <memory>
+#include <mutex>
#include <string_view>
namespace cru::log {
@@ -76,4 +78,31 @@ void Logger::Log(LogLevel level, StringView tag, StringView message) {
LogLevelToString(level), tag, message));
}
}
+
+namespace {
+std::mutex stdio_lock;
+
+void WriteStdio(LogLevel level, StringView s) {
+ std::string m = s.ToString().ToUtf8();
+
+ if (level == LogLevel::Error) {
+ std::cerr << m;
+ } else {
+ std::cout << m;
+ }
+}
+} // namespace
+
+StdioLogSource::StdioLogSource(bool use_lock) : use_lock_(use_lock) {}
+
+StdioLogSource::~StdioLogSource() {}
+
+void StdioLogSource::Write(LogLevel level, StringView s) {
+ if (use_lock_) {
+ std::lock_guard<std::mutex> guard(stdio_lock);
+ WriteStdio(level, s);
+ } else {
+ WriteStdio(level, s);
+ }
+}
} // namespace cru::log
diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp
index 041184c6..c22f80fc 100644
--- a/src/osx/graphics/quartz/Painter.cpp
+++ b/src/osx/graphics/quartz/Painter.cpp
@@ -1,14 +1,32 @@
#include "cru/osx/graphics/quartz/Painter.hpp"
+#include "cru/common/Logger.hpp"
#include "cru/osx/graphics/quartz/Brush.hpp"
#include "cru/osx/graphics/quartz/Convert.hpp"
#include "cru/osx/graphics/quartz/Geometry.hpp"
+#include "cru/osx/graphics/quartz/TextLayout.hpp"
#include "cru/platform/Check.hpp"
#include "cru/platform/Exception.hpp"
+#include "cru/platform/graphics/util/Painter.hpp"
namespace cru::platform::graphics::osx::quartz {
+QuartzCGContextPainter::QuartzCGContextPainter(
+ IGraphicsFactory* graphics_factory, CGContextRef cg_context,
+ bool auto_release, const Size& size,
+ std::function<void(QuartzCGContextPainter*)> on_end_draw)
+ : OsxQuartzResource(graphics_factory),
+ cg_context_(cg_context),
+ auto_release_(auto_release),
+ size_(size),
+ on_end_draw_(std::move(on_end_draw)) {
+ Expects(cg_context);
+ log::TagDebug(log_tag,
+ u"Created with CGContext: {}, Auto Release: {}, Size: {}.",
+ cg_context, auto_release, size_);
+}
+
QuartzCGContextPainter::~QuartzCGContextPainter() {
- EndDraw();
+ DoEndDraw();
if (auto_release_) {
CGContextRelease(cg_context_);
cg_context_ = nullptr;
@@ -29,13 +47,12 @@ void QuartzCGContextPainter::SetTransform(const Matrix& matrix) {
void QuartzCGContextPainter::Clear(const Color& color) {
Validate();
- CGColorRef c =
- CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(),
- color.GetFloatBlue(), color.GetFloatAlpha());
- CGContextSetFillColorWithColor(cg_context_, c);
- CGColorRelease(c);
-
+ CGContextSetRGBFillColor(cg_context_, color.GetFloatRed(),
+ color.GetFloatGreen(), color.GetFloatBlue(),
+ color.GetFloatAlpha());
CGContextFillRect(cg_context_, Convert(Rect{Point{}, size_}));
+
+ log::TagDebug(log_tag, u"Clear with color {}, size {}.", color, size_);
}
void QuartzCGContextPainter::DrawLine(const Point& start, const Point& end,
@@ -98,7 +115,15 @@ void QuartzCGContextPainter::FillGeometry(IGeometry* geometry, IBrush* brush) {
void QuartzCGContextPainter::DrawText(const Point& offset,
ITextLayout* text_layout, IBrush* brush) {
- // TODO: Implement this.
+ Validate();
+
+ auto tl = CheckPlatform<OsxCTTextLayout>(text_layout, GetPlatformId());
+ auto b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
+
+ util::WithTransform(this, Matrix::Translation(offset),
+ [this, tl, b](IPainter*) {
+ CTFrameDraw(tl->GetCTFrameRef(), cg_context_);
+ });
}
void QuartzCGContextPainter::PushLayer(const Rect& bounds) {
@@ -109,10 +134,16 @@ void QuartzCGContextPainter::PopLayer() {
// TODO: Implement this.
}
-void QuartzCGContextPainter::EndDraw() {
+void QuartzCGContextPainter::EndDraw() { DoEndDraw(); }
+
+void QuartzCGContextPainter::DoEndDraw() {
if (cg_context_) {
+ on_end_draw_(this);
+
CGContextFlush(cg_context_);
CGContextSynchronize(cg_context_);
+
+ log::TagDebug(log_tag, u"End draw and flush.");
}
}
diff --git a/src/osx/gui/UiApplication.mm b/src/osx/gui/UiApplication.mm
index 4ac3d1df..11763af6 100644
--- a/src/osx/gui/UiApplication.mm
+++ b/src/osx/gui/UiApplication.mm
@@ -1,5 +1,6 @@
#include "cru/osx/gui/UiApplication.hpp"
+#include "cru/common/Logger.hpp"
#include "cru/osx/graphics/quartz/Factory.hpp"
#include "cru/osx/gui/Cursor.hpp"
#include "cru/osx/gui/Window.hpp"
@@ -66,6 +67,9 @@ void OsxUiApplicationPrivate::CallQuitHandlers() {
OsxUiApplication::OsxUiApplication()
: OsxGuiResource(this), p_(new details::OsxUiApplicationPrivate(this)) {
+ // Add stdio logger.
+ log::Logger::GetInstance()->AddSource(std::make_unique<log::StdioLogSource>());
+
[NSApp setDelegate:p_->app_delegate_];
p_->quartz_graphics_factory_ = std::make_unique<graphics::osx::quartz::QuartzGraphicsFactory>();
p_->cursor_manager_ = std::make_unique<OsxCursorManager>(this);
diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm
index ce28e8a2..d1d6ae8c 100644
--- a/src/osx/gui/Window.mm
+++ b/src/osx/gui/Window.mm
@@ -1,6 +1,7 @@
#include "cru/osx/gui/Window.hpp"
#include "CursorPrivate.h"
+#include "cru/common/Logger.hpp"
#include "cru/common/Range.hpp"
#include "cru/osx/Convert.hpp"
#include "cru/osx/graphics/quartz/Convert.hpp"
@@ -14,6 +15,7 @@
#include "cru/platform/gui/Cursor.hpp"
#include "cru/platform/gui/InputMethod.hpp"
#include "cru/platform/gui/Keyboard.hpp"
+#include "cru/platform/gui/TimerHelper.hpp"
#include "cru/platform/gui/Window.hpp"
#include <AppKit/NSGraphicsContext.h>
@@ -22,16 +24,17 @@
#include <Foundation/NSAttributedString.h>
#include <Foundation/NSString.h>
+#include <gsl/gsl_assert>
#include <limits>
#include <memory>
using cru::platform::osx::Convert;
-@interface WindowDelegate : NSObject <NSWindowDelegate>
+@interface CruWindowDelegate : NSObject <NSWindowDelegate>
- (id)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p;
@end
-@interface Window : NSWindow
+@interface CruWindow : NSWindow
- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p
contentRect:(NSRect)contentRect
style:(NSWindowStyleMask)style;
@@ -48,7 +51,12 @@ using cru::platform::osx::Convert;
- (void)keyUp:(NSEvent*)event;
@end
-@interface InputClient : NSObject <NSTextInputClient>
+@interface CruView : NSView
+- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p
+ frame:(cru::platform::Rect)frame;
+@end
+
+@interface CruInputClient : NSObject <NSTextInputClient>
- (id)init:(cru::platform::gui::osx::details::OsxInputMethodContextPrivate*)p;
@end
@@ -89,6 +97,8 @@ class OsxWindowPrivate {
void OnWindowDidUpdate();
void OnWindowDidResize();
+ CGLayerRef GetDrawLayer() { return draw_layer_; }
+
private:
void UpdateCursor();
@@ -101,32 +111,38 @@ class OsxWindowPrivate {
Rect content_rect_;
NSWindow* window_;
- WindowDelegate* window_delegate_;
- NSGraphicsContext* graphics_context_;
+ CruWindowDelegate* window_delegate_;
+
+ CGLayerRef draw_layer_;
bool mouse_in_ = false;
std::shared_ptr<OsxCursor> cursor_ = nullptr;
std::unique_ptr<OsxInputMethodContext> input_method_context_;
+
+ TimerAutoCanceler draw_timer_;
};
void OsxWindowPrivate::OnWindowWillClose() {
osx_window_->destroy_event_.Raise(nullptr);
window_ = nil;
- graphics_context_ = nil;
+ CGLayerRelease(draw_layer_);
}
void OsxWindowPrivate::OnWindowDidExpose() { osx_window_->RequestRepaint(); }
void OsxWindowPrivate::OnWindowDidUpdate() {}
void OsxWindowPrivate::OnWindowDidResize() {
- osx_window_->resize_event_.Raise(osx_window_->GetClientSize());
-
NSRect rect = [NSWindow contentRectForFrameRect:[window_ frame]
styleMask:CalcWindowStyleMask(frame_)];
-
content_rect_ = cru::platform::graphics::osx::quartz::Convert(rect);
+ osx_window_->resize_event_.Raise(osx_window_->GetClientSize());
+
+ CGLayerRelease(draw_layer_);
+ draw_layer_ = CGLayerCreateWithContext(nullptr, rect.size, nullptr);
+ Ensures(draw_layer_);
+
osx_window_->RequestRepaint();
}
@@ -175,7 +191,7 @@ void OsxWindowPrivate::UpdateCursor() {
OsxWindow::OsxWindow(OsxUiApplication* ui_application, INativeWindow* parent, bool frame)
: OsxGuiResource(ui_application), p_(new details::OsxWindowPrivate(this)) {
- p_->window_delegate_ = [[WindowDelegate alloc] init:p_.get()];
+ p_->window_delegate_ = [[CruWindowDelegate alloc] init:p_.get()];
p_->parent_ = parent;
@@ -251,14 +267,23 @@ void OsxWindow::SetWindowRect(const Rect& rect) {
}
void OsxWindow::RequestRepaint() {
- GetUiApplication()->SetImmediate([this] { paint_event_.Raise(nullptr); });
+ if (!p_->draw_timer_) {
+ p_->draw_timer_ = GetUiApplication()->SetImmediate([this] {
+ this->paint_event_.Raise(nullptr);
+ this->p_->draw_timer_.Release();
+ });
+ }
}
std::unique_ptr<graphics::IPainter> OsxWindow::BeginPaint() {
- CGContextRef cg_context = [p_->graphics_context_ CGContext];
+ CGContextRef cg_context = CGLayerGetContext(p_->draw_layer_);
return std::make_unique<cru::platform::graphics::osx::quartz::QuartzCGContextPainter>(
- GetUiApplication()->GetGraphicsFactory(), cg_context, false, GetClientSize());
+ GetUiApplication()->GetGraphicsFactory(), cg_context, false, GetClientSize(),
+ [this](graphics::osx::quartz::QuartzCGContextPainter*) {
+ log::Debug(u"Finish painting and invalidate view.");
+ [[p_->window_ contentView] setNeedsDisplay:YES];
+ });
}
void OsxWindow::CreateWindow() {
@@ -267,11 +292,20 @@ void OsxWindow::CreateWindow() {
NSWindowStyleMask style_mask = CalcWindowStyleMask(p_->frame_);
- p_->window_ = [[Window alloc] init:p_.get() contentRect:content_rect style:style_mask];
+ p_->window_ = [[CruWindow alloc] init:p_.get() contentRect:content_rect style:style_mask];
[p_->window_ setDelegate:p_->window_delegate_];
- p_->graphics_context_ = [NSGraphicsContext graphicsContextWithWindow:p_->window_];
+ NSView* content_view = [[CruView alloc] init:p_.get()
+ frame:Rect(Point{}, p_->content_rect_.GetSize())];
+
+ [p_->window_ setContentView:content_view];
+
+ p_->draw_layer_ = CGLayerCreateWithContext(
+ nullptr, cru::platform::graphics::osx::quartz::Convert(p_->content_rect_.GetSize()), nullptr);
+ Ensures(p_->draw_layer_);
+
+ RequestRepaint();
}
Point OsxWindow::GetMousePosition() {
@@ -405,7 +439,7 @@ IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionEvent() {
IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_; }
}
-@implementation Window {
+@implementation CruWindow {
cru::platform::gui::osx::details::OsxWindowPrivate* _p;
}
@@ -524,7 +558,29 @@ IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_
}
@end
-@implementation WindowDelegate {
+@implementation CruView {
+ cru::platform::gui::osx::details::OsxWindowPrivate* _p;
+}
+
+- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p
+ frame:(cru::platform::Rect)frame {
+ [super initWithFrame:cru::platform::graphics::osx::quartz::Convert(frame)];
+ _p = p;
+
+ return self;
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ cru::log::TagDebug(u"CruView", u"Begin to draw layer in view.");
+ auto cg_context = [[NSGraphicsContext currentContext] CGContext];
+ auto layer = _p->GetDrawLayer();
+ Ensures(layer);
+ CGContextDrawLayerAtPoint(cg_context, CGPointMake(0, 0), layer);
+}
+
+@end
+
+@implementation CruWindowDelegate {
cru::platform::gui::osx::details::OsxWindowPrivate* _p;
}
@@ -550,7 +606,7 @@ IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_
}
@end
-@implementation InputClient {
+@implementation CruInputClient {
cru::platform::gui::osx::details::OsxInputMethodContextPrivate* _p;
NSMutableAttributedString* _text;
}