[WRTjs] Refactor popup
[platform/framework/web/chromium-efl.git] / wrt / src / browser / wrt_frame_view.cc
1 // Copyright 2023 Samsung Electronics. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "wrt/src/browser/wrt_frame_view.h"
6
7 #include "base/files/file_util.h"
8 #include "base/task/task_traits.h"
9 #include "base/task/thread_pool.h"
10 #include "services/data_decoder/public/cpp/decode_image.h"
11 #include "ui/aura/window.h"
12 #include "ui/base/hit_test.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/image/image_skia_operations.h"
15 #include "ui/views/controls/image_view.h"
16 #include "ui/views/background.h"
17 #include "ui/views/border.h"
18 #include "ui/views/painter.h"
19 #include "ui/views/widget/widget.h"
20 #include "ui/views/widget/widget_delegate.h"
21
22 namespace wrt {
23
24 namespace {
25
26 const int kResizeInsideBoundsSize = 5;
27 const int kResizeAreaCornerSize = 16;
28
29 std::string ReadFileToString(const base::FilePath& path) {
30   std::string result;
31   if (!base::ReadFileToString(path, &result)) {
32     LOG(WARNING) << "Failed reading file";
33     result.clear();
34   }
35
36   return result;
37 }
38
39 void DecodeImageData(data_decoder::DecodeImageCallback callback,
40                      const std::string& data) {
41   if (data.empty()) {
42     std::move(callback).Run(SkBitmap());
43     return;
44   }
45   data_decoder::DecodeImageIsolated(
46       base::as_bytes(base::make_span(data)),
47       data_decoder::mojom::ImageCodec::kDefault,
48       true, data_decoder::kDefaultMaxSizeInBytes, gfx::Size(),
49       std::move(callback));
50 }
51
52 void DecodeImageFile(const base::FilePath& file_path,
53                      data_decoder::DecodeImageCallback callback) {
54   base::ThreadPool::PostTaskAndReplyWithResult(
55       FROM_HERE,
56       {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
57        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
58       base::BindOnce(&ReadFileToString, file_path),
59       base::BindOnce(&DecodeImageData, std::move(callback)));
60 }
61
62 }  // namespace
63
64 // static
65 const char WRTFrameView::kViewClassName[] = "WRTFrameView";
66
67 WRTFrameView::WRTFrameView() = default;
68
69 WRTFrameView::~WRTFrameView() = default;
70
71 int WRTFrameView::ResizingBorderHitTest(const gfx::Point& point) {
72   gfx::Insets resize_border(kResizeInsideBoundsSize);
73
74   // to be used for resize handles.
75   bool can_ever_resize = GetWidget()->widget_delegate()
76                              ? GetWidget()->widget_delegate()->CanResize()
77                              : false;
78
79   // https://github.com/electron/electron/issues/611
80   // If window isn't resizable, we should always return HTNOWHERE, otherwise the
81   // hover state of DOM will not be cleared probably.
82   if (!can_ever_resize)
83     return HTNOWHERE;
84
85   // Don't allow overlapping resize handles when the window is maximized or
86   // fullscreen, as it can't be resized in those states.
87   bool allow_overlapping_handles =
88       !GetWidget()->IsMaximized() && !GetWidget()->IsFullscreen();
89   return GetHTComponentForFrame(
90       point, allow_overlapping_handles ? resize_border : gfx::Insets(),
91       kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize);
92 }
93
94 gfx::Rect WRTFrameView::GetBoundsForClientView() const {
95   return bounds();
96 }
97
98 gfx::Rect WRTFrameView::GetWindowBoundsForClientBounds(
99     const gfx::Rect& client_bounds) const {
100   gfx::Rect window_bounds = client_bounds;
101   // Enforce minimum size (1, 1) in case that client_bounds is passed with
102   // empty size. This could occur when the frameless window is being
103   // initialized.
104   if (window_bounds.IsEmpty()) {
105     window_bounds.set_width(1);
106     window_bounds.set_height(1);
107   }
108   return window_bounds;
109 }
110
111 int WRTFrameView::NonClientHitTest(const gfx::Point& cursor) {
112   if (GetWidget()->IsFullscreen())
113     return HTCLIENT;
114
115   // Support resizing frameless window by dragging the border.
116   int frame_component = ResizingBorderHitTest(cursor);
117   if (frame_component != HTNOWHERE)
118     return frame_component;
119
120   return HTCLIENT;
121 }
122
123 void WRTFrameView::GetWindowMask(const gfx::Size& size, SkPath* window_mask) {}
124
125 void WRTFrameView::ResetWindowControls() {}
126
127 void WRTFrameView::UpdateWindowIcon() {}
128
129 void WRTFrameView::UpdateWindowTitle() {}
130
131 void WRTFrameView::SizeConstraintsChanged() {}
132
133 views::View* WRTFrameView::TargetForRect(views::View* root,
134                                           const gfx::Rect& rect) {
135   CHECK_EQ(root, this);
136
137   if (NonClientHitTest(rect.origin()) != HTCLIENT)
138     return this;
139
140   return NonClientFrameView::TargetForRect(root, rect);
141 }
142
143 gfx::Size WRTFrameView::CalculatePreferredSize() const {
144   return GetWidget()->non_client_view()
145       ->GetWindowBoundsForClientBounds(
146           gfx::Rect(GetWidget()->client_view()->GetPreferredSize()))
147       .size();
148 }
149
150 gfx::Size WRTFrameView::GetMinimumSize() const {
151   return gfx::Size(0, 0);
152 }
153
154 gfx::Size WRTFrameView::GetMaximumSize() const {
155   return gfx::Size(INT_MAX, INT_MAX);
156 }
157
158 const char* WRTFrameView::GetClassName() const {
159   return kViewClassName;
160 }
161
162 void WRTFrameView::SetBackgroundColor(SkColor color) {
163   SetBackground(views::CreateSolidBackground(color));
164 }
165
166 void WRTFrameView::SetImageBorder(const base::FilePath& file_path,
167                                   const gfx::Insets& insets) {
168   image_border_insets_ = insets;
169   ++image_loading_count_;
170   DecodeImageFile(file_path, base::BindOnce(&WRTFrameView::OnImageBorderDecoded,
171                                             base::Unretained(this)));
172 }
173
174 void WRTFrameView::OnImageBorderDecoded(const SkBitmap& bitmap) {
175   SetBorder(views::CreateBorderPainter(
176       views::Painter::CreateImagePainter(
177           gfx::ImageSkia::CreateFrom1xBitmap(bitmap), image_border_insets_),
178       gfx::Insets()));
179   OnImageLoaded();
180 }
181
182 void WRTFrameView::SetImage(const base::FilePath& file_path) {
183   image_view_ = AddChildView(std::make_unique<views::ImageView>());
184   image_view_->SetSize(size());
185   ++image_loading_count_;
186   DecodeImageFile(file_path, base::BindOnce(&WRTFrameView::OnImageDecoded,
187                                             base::Unretained(this)));
188 }
189
190 void WRTFrameView::OnImageDecoded(const SkBitmap& bitmap) {
191   gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
192   image_view_->SetImage(
193       ui::ImageModel::FromImageSkia(ResizeImage(image, image_view_->size())));
194   OnImageLoaded();
195 }
196
197 gfx::ImageSkia WRTFrameView::ResizeImage(const gfx::ImageSkia& image,
198                                          const gfx::Size& view_size) {
199   if (image.isNull())
200     return gfx::ImageSkia();
201
202   const double image_width = image.width();
203   const double image_height = image.height();
204   const double view_width = view_size.width();
205   const double view_height = view_size.height();
206   const double horizontal_ratio = view_width / image_width;
207   const double vertical_ratio = view_height / image_height;
208   const double image_ratio = image_height / image_width;
209   const double view_ratio = view_height / view_width;
210
211   // If the image and the container view has the same orientation, e.g. both
212   // portrait, the |scale| will make the image filled the whole view with
213   // possible cropping on one direction. If they are in different orientation,
214   // the |scale| will display the image in the view without any cropping, but
215   // with empty background.
216   const double scale = (image_ratio - 1) * (view_ratio - 1) > 0
217                            ? std::max(horizontal_ratio, vertical_ratio)
218                            : std::min(horizontal_ratio, vertical_ratio);
219   const gfx::Size& resized = gfx::ScaleToCeiledSize(image.size(), scale);
220   return gfx::ImageSkiaOperations::CreateResizedImage(
221       image, skia::ImageOperations::RESIZE_BEST, resized);
222 }
223
224 void WRTFrameView::ShowWidgetWhenReady() {
225   if (!image_loading_count_) {
226     GetWidget()->Show();
227     return;
228   }
229   need_to_show_widget_ = true;
230 }
231
232 void WRTFrameView::OnImageLoaded() {
233   if (--image_loading_count_ == 0 && need_to_show_widget_) {
234     need_to_show_widget_ = false;
235     GetWidget()->Show();
236   }
237 }
238
239 }  // namespace wrt