Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(811)

Side by Side Diff: apps/moterm/moterm_view.cc

Issue 1556683004: Port Moterm to Mozart. (Closed) Base URL: git@github.com:domokit/mojo.git@moz-16
Patch Set: fix nits Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « apps/moterm/moterm_view.h ('k') | examples/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "apps/moterm/moterm_view.h" 5 #include "apps/moterm/moterm_view.h"
6 6
7 #ifndef GL_GLEXT_PROTOTYPES 7 #ifndef GL_GLEXT_PROTOTYPES
8 #define GL_GLEXT_PROTOTYPES 8 #define GL_GLEXT_PROTOTYPES
9 #endif 9 #endif
10 10
11 #include <GLES2/gl2.h> 11 #include <GLES2/gl2.h>
12 #include <GLES2/gl2ext.h> 12 #include <GLES2/gl2ext.h>
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <string> 15 #include <string>
16 16
17 #include "apps/moterm/key_util.h" 17 #include "apps/moterm/key_util.h"
18 #include "base/bind.h"
18 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "mojo/public/cpp/application/connect.h"
19 #include "mojo/public/cpp/bindings/interface_request.h" 21 #include "mojo/public/cpp/bindings/interface_request.h"
20 #include "mojo/services/files/interfaces/file.mojom.h" 22 #include "mojo/services/files/interfaces/file.mojom.h"
21 #include "mojo/services/files/interfaces/types.mojom.h" 23 #include "mojo/services/files/interfaces/types.mojom.h"
22 #include "mojo/services/input_events/interfaces/input_event_constants.mojom.h"
23 #include "mojo/services/input_events/interfaces/input_events.mojom.h"
24 #include "mojo/services/terminal/interfaces/terminal_client.mojom.h" 24 #include "mojo/services/terminal/interfaces/terminal_client.mojom.h"
25 #include "skia/ext/refptr.h" 25 #include "mojo/skia/ganesh_texture_surface.h"
26 #include "third_party/dejavu-fonts-ttf-2.34/kDejaVuSansMonoRegular.h" 26 #include "third_party/dejavu-fonts-ttf-2.34/kDejaVuSansMonoRegular.h"
27 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/skia/include/core/SkCanvas.h" 28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkColor.h" 29 #include "third_party/skia/include/core/SkColor.h"
30 #include "third_party/skia/include/core/SkImageInfo.h" 30 #include "third_party/skia/include/core/SkImageInfo.h"
31 #include "third_party/skia/include/core/SkPaint.h" 31 #include "third_party/skia/include/core/SkPaint.h"
32 #include "third_party/skia/include/core/SkRect.h" 32 #include "third_party/skia/include/core/SkRect.h"
33 #include "third_party/skia/include/core/SkStream.h" 33 #include "third_party/skia/include/core/SkStream.h"
34 #include "third_party/skia/include/core/SkXfermode.h" 34 #include "third_party/skia/include/core/SkXfermode.h"
35 35
36 namespace { 36 constexpr uint32_t kMotermImageResourceId = 1;
37 37 constexpr uint32_t kRootNodeId = mojo::gfx::composition::kSceneRootNodeId;
38 const GLint kTextureFormat =
39 (kN32_SkColorType == kRGBA_8888_SkColorType) ? GL_RGBA : GL_BGRA_EXT;
40
41 mojo::Size RectToSize(const mojo::Rect& rect) {
42 mojo::Size size;
43 size.width = rect.width;
44 size.height = rect.height;
45 return size;
46 }
47
48 } // namespace
49 38
50 MotermView::MotermView( 39 MotermView::MotermView(
51 mojo::Shell* shell, 40 mojo::ApplicationImpl* app_impl,
52 mojo::View* view, 41 mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request,
53 mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request) 42 const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback)
54 : view_(view), 43 : GaneshView(app_impl, "Moterm", create_view_callback),
55 gl_helper_(this, 44 choreographer_(scene(), this),
56 shell, 45 input_handler_(view_service_provider(), this),
57 kTextureFormat,
58 false,
59 RectToSize(view->bounds())),
60 model_(MotermModel::Size(240, 160), MotermModel::Size(24, 80), this), 46 model_(MotermModel::Size(240, 160), MotermModel::Size(24, 80), this),
61 frame_pending_(false),
62 force_next_draw_(false), 47 force_next_draw_(false),
63 ascent_(0), 48 ascent_(0),
64 line_height_(0), 49 line_height_(0),
65 advance_width_(0), 50 advance_width_(0),
66 keypad_application_mode_(false) { 51 keypad_application_mode_(false) {
67 // TODO(vtl): |service_provider_impl_|'s ctor doesn't like an invalid request, 52 // TODO(vtl): |service_provider_impl_|'s ctor doesn't like an invalid request,
68 // so we have to conditionally, explicitly bind. 53 // so we have to conditionally, explicitly bind.
69 if (service_provider_request.is_pending()) { 54 if (service_provider_request.is_pending()) {
70 service_provider_impl_.Bind(service_provider_request.Pass()); 55 service_provider_impl_.Bind(service_provider_request.Pass());
71 service_provider_impl_.AddService<mojo::terminal::Terminal>(this); 56 service_provider_impl_.AddService<mojo::terminal::Terminal>(this);
(...skipping 10 matching lines...) Expand all
82 // Figure out appropriate metrics. 67 // Figure out appropriate metrics.
83 SkPaint::FontMetrics fm = {}; 68 SkPaint::FontMetrics fm = {};
84 fg_paint.getFontMetrics(&fm); 69 fg_paint.getFontMetrics(&fm);
85 ascent_ = static_cast<int>(ceilf(-fm.fAscent)); 70 ascent_ = static_cast<int>(ceilf(-fm.fAscent));
86 line_height_ = ascent_ + static_cast<int>(ceilf(fm.fDescent + fm.fLeading)); 71 line_height_ = ascent_ + static_cast<int>(ceilf(fm.fDescent + fm.fLeading));
87 DCHECK_GT(line_height_, 0); 72 DCHECK_GT(line_height_, 0);
88 // To figure out the advance width, measure an X. Better hope the font is 73 // To figure out the advance width, measure an X. Better hope the font is
89 // monospace. 74 // monospace.
90 advance_width_ = static_cast<int>(ceilf(fg_paint.measureText("X", 1))); 75 advance_width_ = static_cast<int>(ceilf(fg_paint.measureText("X", 1)));
91 DCHECK_GT(advance_width_, 0); 76 DCHECK_GT(advance_width_, 0);
92
93 view_->AddObserver(this);
94
95 // Force an initial draw.
96 Draw(true);
97 } 77 }
98 78
99 MotermView::~MotermView() { 79 MotermView::~MotermView() {
100 if (driver_) 80 if (driver_)
101 driver_->Detach(); 81 driver_->Detach();
102 } 82 }
103 83
104 void MotermView::OnViewDestroyed(mojo::View* view) { 84 void MotermView::OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params,
105 DCHECK_EQ(view, view_); 85 mojo::Array<uint32_t> children_needing_layout,
106 view_->RemoveObserver(this); 86 const OnLayoutCallback& callback) {
107 delete this; 87 view_size_.width = layout_params->constraints->max_width;
88 view_size_.height = layout_params->constraints->max_height;
89
90 ScheduleDraw(true);
91
92 auto info = mojo::ui::ViewLayoutResult::New();
93 info->size = view_size_.Clone();
94 callback.Run(info.Pass());
108 } 95 }
109 96
110 void MotermView::OnViewBoundsChanged(mojo::View* view, 97 void MotermView::OnEvent(mojo::EventPtr event,
111 const mojo::Rect& old_bounds, 98 const OnEventCallback& callback) {
112 const mojo::Rect& new_bounds) { 99 if (event->action == mojo::EventType::KEY_PRESSED) {
113 DCHECK_EQ(view, view_); 100 OnKeyPressed(event.Pass());
114 gl_helper_.SetSurfaceSize(RectToSize(view_->bounds())); 101 callback.Run(true);
115 bitmap_device_.clear(); 102 } else {
116 Draw(true); 103 callback.Run(false);
117 } 104 }
118
119 void MotermView::OnViewInputEvent(mojo::View* view,
120 const mojo::EventPtr& event) {
121 if (event->action == mojo::EventType::KEY_PRESSED)
122 OnKeyPressed(event);
123 }
124
125 void MotermView::OnSurfaceIdChanged(mojo::SurfaceIdPtr surface_id) {
126 view_->SetSurfaceId(surface_id.Pass());
127 }
128
129 void MotermView::OnContextLost() {
130 // TODO(vtl): We'll need to force a draw when we regain a context.
131 }
132
133 void MotermView::OnFrameDisplayed(uint32_t frame_id) {
134 DCHECK(frame_pending_);
135 frame_pending_ = false;
136 Draw(false);
137 } 105 }
138 106
139 void MotermView::OnResponse(const void* buf, size_t size) { 107 void MotermView::OnResponse(const void* buf, size_t size) {
140 if (driver_) 108 if (driver_)
141 driver_->SendData(buf, size); 109 driver_->SendData(buf, size);
142 } 110 }
143 111
144 void MotermView::OnSetKeypadMode(bool application_mode) { 112 void MotermView::OnSetKeypadMode(bool application_mode) {
145 keypad_application_mode_ = application_mode; 113 keypad_application_mode_ = application_mode;
146 } 114 }
147 115
148 void MotermView::OnDataReceived(const void* bytes, size_t num_bytes) { 116 void MotermView::OnDataReceived(const void* bytes, size_t num_bytes) {
149 model_.ProcessInput(bytes, num_bytes, &model_state_changes_); 117 model_.ProcessInput(bytes, num_bytes, &model_state_changes_);
150 Draw(false); 118 ScheduleDraw(false);
151 } 119 }
152 120
153 void MotermView::OnClosed() { 121 void MotermView::OnClosed() {
154 DCHECK(driver_); 122 DCHECK(driver_);
155 driver_->Detach(); 123 driver_->Detach();
156 driver_.reset(); 124 driver_.reset();
157 125
158 OnDestroyed(); 126 OnDestroyed();
159 } 127 }
160 128
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 void MotermView::GetSize(const GetSizeCallback& callback) { 186 void MotermView::GetSize(const GetSizeCallback& callback) {
219 MotermModel::Size size = model_.GetSize(); 187 MotermModel::Size size = model_.GetSize();
220 callback.Run(mojo::files::Error::OK, size.rows, size.columns); 188 callback.Run(mojo::files::Error::OK, size.rows, size.columns);
221 } 189 }
222 190
223 void MotermView::SetSize(uint32_t rows, 191 void MotermView::SetSize(uint32_t rows,
224 uint32_t columns, 192 uint32_t columns,
225 bool reset, 193 bool reset,
226 const SetSizeCallback& callback) { 194 const SetSizeCallback& callback) {
227 if (!rows) { 195 if (!rows) {
228 rows = std::max(1u, std::min(MotermModel::kMaxRows, 196 rows = std::max(
229 static_cast<uint32_t>(view_->bounds().height) / 197 1u, std::min(MotermModel::kMaxRows,
230 line_height_)); 198 static_cast<uint32_t>(view_size_.height) / line_height_));
231 } 199 }
232 if (!columns) { 200 if (!columns) {
233 columns = 201 columns = std::max(
234 std::max(1u, std::min(MotermModel::kMaxColumns, 202 1u, std::min(MotermModel::kMaxColumns,
235 static_cast<uint32_t>(view_->bounds().width) / 203 static_cast<uint32_t>(view_size_.width) / advance_width_));
236 advance_width_));
237 } 204 }
238 205
239 model_.SetSize(MotermModel::Size(rows, columns), reset); 206 model_.SetSize(MotermModel::Size(rows, columns), reset);
240 callback.Run(mojo::files::Error::OK, rows, columns); 207 callback.Run(mojo::files::Error::OK, rows, columns);
241 208
242 Draw(false); 209 ScheduleDraw(false);
243 } 210 }
244 211
245 void MotermView::Draw(bool force) { 212 void MotermView::ScheduleDraw(bool force) {
246 // TODO(vtl): See TODO above |frame_pending_| in the class declaration. 213 if (view_size_.width == 0 || view_size_.height == 0 ||
247 if (frame_pending_) { 214 (!model_state_changes_.IsDirty() && !force && !force_next_draw_)) {
248 force_next_draw_ |= force; 215 force_next_draw_ |= force;
249 return; 216 return;
250 } 217 }
218 force_next_draw_ = false;
219 choreographer_.ScheduleDraw();
220 }
251 221
252 force |= force_next_draw_; 222 void MotermView::OnDraw(const mojo::gfx::composition::FrameInfo& frame_info,
253 force_next_draw_ = false; 223 const base::TimeDelta& time_delta) {
254 224 // TODO(vtl): Draw only the dirty region(s)?
255 if (!force && !model_state_changes_.IsDirty())
256 return;
257
258 // TODO(vtl): If |!force|, draw only the dirty region(s)?
259 model_state_changes_.Reset(); 225 model_state_changes_.Reset();
260 226
261 int32_t width = view_->bounds().width; 227 mojo::Rect bounds;
262 int32_t height = view_->bounds().height; 228 bounds.width = view_size_.width;
263 DCHECK_GT(width, 0); 229 bounds.height = view_size_.height;
264 DCHECK_GT(height, 0);
265 230
266 if (!bitmap_device_) { 231 auto update = mojo::gfx::composition::SceneUpdate::New();
267 bitmap_device_ = skia::AdoptRef(SkBitmapDevice::Create(SkImageInfo::Make( 232 mojo::gfx::composition::ResourcePtr moterm_resource =
268 width, height, kN32_SkColorType, kOpaque_SkAlphaType))); 233 ganesh_renderer()->DrawCanvas(
269 } 234 view_size_,
235 base::Bind(&MotermView::DrawContent, base::Unretained(this)));
236 DCHECK(moterm_resource);
237 update->resources.insert(kMotermImageResourceId, moterm_resource.Pass());
270 238
271 SkCanvas canvas(bitmap_device_.get()); 239 auto root_node = mojo::gfx::composition::Node::New();
272 canvas.clear(SK_ColorBLACK); 240 root_node->op = mojo::gfx::composition::NodeOp::New();
241 root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New());
242 root_node->op->get_image()->content_rect = bounds.Clone();
243 root_node->op->get_image()->image_resource_id = kMotermImageResourceId;
244 update->nodes.insert(kRootNodeId, root_node.Pass());
245
246 auto metadata = mojo::gfx::composition::SceneMetadata::New();
247 metadata->presentation_time = frame_info.presentation_time;
248
249 scene()->Update(update.Pass());
250 scene()->Publish(metadata.Pass());
251 }
252
253 void MotermView::DrawContent(SkCanvas* canvas) {
254 canvas->clear(SK_ColorBLACK);
273 255
274 SkPaint bg_paint; 256 SkPaint bg_paint;
275 bg_paint.setStyle(SkPaint::kFill_Style); 257 bg_paint.setStyle(SkPaint::kFill_Style);
276 258
277 SkPaint fg_paint; 259 SkPaint fg_paint;
278 fg_paint.setTypeface(regular_typeface_.get()); 260 fg_paint.setTypeface(regular_typeface_.get());
279 fg_paint.setTextSize(16); 261 fg_paint.setTextSize(16);
280 fg_paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); 262 fg_paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
281 263
282 MotermModel::Size size = model_.GetSize(); 264 MotermModel::Size size = model_.GetSize();
283 int y = 0; 265 int y = 0;
284 for (unsigned i = 0; i < size.rows; i++, y += line_height_) { 266 for (unsigned i = 0; i < size.rows; i++, y += line_height_) {
285 int x = 0; 267 int x = 0;
286 for (unsigned j = 0; j < size.columns; j++, x += advance_width_) { 268 for (unsigned j = 0; j < size.columns; j++, x += advance_width_) {
287 MotermModel::CharacterInfo ch = 269 MotermModel::CharacterInfo ch =
288 model_.GetCharacterInfoAt(MotermModel::Position(i, j)); 270 model_.GetCharacterInfoAt(MotermModel::Position(i, j));
289 271
290 // Paint the background. 272 // Paint the background.
291 bg_paint.setColor(SkColorSetRGB(ch.background_color.red, 273 bg_paint.setColor(SkColorSetRGB(ch.background_color.red,
292 ch.background_color.green, 274 ch.background_color.green,
293 ch.background_color.blue)); 275 ch.background_color.blue));
294 canvas.drawRect(SkRect::MakeXYWH(x, y, advance_width_, line_height_), 276 canvas->drawRect(SkRect::MakeXYWH(x, y, advance_width_, line_height_),
295 bg_paint); 277 bg_paint);
296 278
297 // Paint the foreground. 279 // Paint the foreground.
298 if (ch.code_point) { 280 if (ch.code_point) {
299 uint32_t flags = SkPaint::kAntiAlias_Flag; 281 uint32_t flags = SkPaint::kAntiAlias_Flag;
300 // TODO(vtl): Use real bold font? 282 // TODO(vtl): Use real bold font?
301 if ((ch.attributes & MotermModel::kAttributesBold)) 283 if ((ch.attributes & MotermModel::kAttributesBold))
302 flags |= SkPaint::kFakeBoldText_Flag; 284 flags |= SkPaint::kFakeBoldText_Flag;
303 if ((ch.attributes & MotermModel::kAttributesUnderline)) 285 if ((ch.attributes & MotermModel::kAttributesUnderline))
304 flags |= SkPaint::kUnderlineText_Flag; 286 flags |= SkPaint::kUnderlineText_Flag;
305 // TODO(vtl): Handle blink, because that's awesome. 287 // TODO(vtl): Handle blink, because that's awesome.
306 fg_paint.setFlags(flags); 288 fg_paint.setFlags(flags);
307 fg_paint.setColor(SkColorSetRGB(ch.foreground_color.red, 289 fg_paint.setColor(SkColorSetRGB(ch.foreground_color.red,
308 ch.foreground_color.green, 290 ch.foreground_color.green,
309 ch.foreground_color.blue)); 291 ch.foreground_color.blue));
310 292
311 canvas.drawText(&ch.code_point, sizeof(ch.code_point), x, y + ascent_, 293 canvas->drawText(&ch.code_point, sizeof(ch.code_point), x, y + ascent_,
312 fg_paint); 294 fg_paint);
313 } 295 }
314 } 296 }
315 } 297 }
316 298
317 if (model_.GetCursorVisibility()) { 299 if (model_.GetCursorVisibility()) {
318 // Draw the cursor. 300 // Draw the cursor.
319 MotermModel::Position cursor_pos = model_.GetCursorPosition(); 301 MotermModel::Position cursor_pos = model_.GetCursorPosition();
320 // Reuse the background paint, but don't just paint over. 302 // Reuse the background paint, but don't just paint over.
321 // TODO(vtl): Consider doing other things. Maybe make it blink, to be extra 303 // TODO(vtl): Consider doing other things. Maybe make it blink, to be extra
322 // annoying. 304 // annoying.
323 // TODO(vtl): Maybe vary how we draw the cursor, depending on if we're 305 // TODO(vtl): Maybe vary how we draw the cursor, depending on if we're
324 // focused and/or active. 306 // focused and/or active.
325 bg_paint.setColor(SK_ColorWHITE); 307 bg_paint.setColor(SK_ColorWHITE);
326 bg_paint.setXfermodeMode(SkXfermode::kDifference_Mode); 308 bg_paint.setXfermodeMode(SkXfermode::kDifference_Mode);
327 canvas.drawRect(SkRect::MakeXYWH(cursor_pos.column * advance_width_, 309 canvas->drawRect(SkRect::MakeXYWH(cursor_pos.column * advance_width_,
328 cursor_pos.row * line_height_, 310 cursor_pos.row * line_height_,
329 advance_width_, line_height_), 311 advance_width_, line_height_),
330 bg_paint); 312 bg_paint);
331 } 313 }
332 314 canvas->flush();
333 canvas.flush();
334
335 const SkBitmap& bitmap(bitmap_device_->accessBitmap(false));
336 // TODO(vtl): Do we need really need to lock/unlock pixels?
337 SkAutoLockPixels pixel_locker(bitmap);
338
339 gl_helper_.StartFrame();
340 // (The texture is already bound.)
341 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, kTextureFormat,
342 GL_UNSIGNED_BYTE, bitmap.getPixels());
343 gl_helper_.EndFrame();
344 frame_pending_ = true;
345 } 315 }
346 316
347 void MotermView::OnKeyPressed(const mojo::EventPtr& key_event) { 317 void MotermView::OnKeyPressed(mojo::EventPtr key_event) {
348 std::string input_sequence = 318 std::string input_sequence =
349 GetInputSequenceForKeyPressedEvent(*key_event, keypad_application_mode_); 319 GetInputSequenceForKeyPressedEvent(*key_event, keypad_application_mode_);
350 if (input_sequence.empty()) 320 if (input_sequence.empty())
351 return; 321 return;
352 322
353 if (driver_) 323 if (driver_)
354 driver_->SendData(input_sequence.data(), input_sequence.size()); 324 driver_->SendData(input_sequence.data(), input_sequence.size());
355 } 325 }
OLDNEW
« no previous file with comments | « apps/moterm/moterm_view.h ('k') | examples/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698