1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "renderer/unix/infolist_window.h"
31
32 #include "base/logging.h"
33 #include "base/mutex.h"
34 #include "protocol/renderer_command.pb.h"
35 #include "protocol/renderer_style.pb.h"
36 #include "renderer/renderer_style_handler.h"
37 #include "renderer/unix/cairo_wrapper.h"
38 #include "renderer/unix/const.h"
39 #include "renderer/unix/draw_tool.h"
40 #include "renderer/unix/font_spec.h"
41 #include "renderer/unix/text_renderer.h"
42
43 namespace mozc {
44 namespace renderer {
45 namespace gtk {
46
47 using mozc::commands::Candidates;
48 using mozc::commands::Information;
49 using mozc::commands::InformationList;
50 using mozc::commands::Output;
51 using mozc::commands::SessionCommand;
52 using mozc::renderer::RendererStyle;
53 using mozc::renderer::RendererStyleHandler;
54
55 namespace {
StyleColorToRGBA(const RendererStyle::RGBAColor & rgbacolor)56 RGBA StyleColorToRGBA(const RendererStyle::RGBAColor &rgbacolor) {
57 const RGBA rgba = { static_cast<uint8>(rgbacolor.r()),
58 static_cast<uint8>(rgbacolor.g()),
59 static_cast<uint8>(rgbacolor.b()),
60 0xFF };
61 return rgba;
62 }
63 } // namespace
64
InfolistWindow(TextRendererInterface * text_renderer,DrawToolInterface * draw_tool,GtkWrapperInterface * gtk,CairoFactoryInterface * cairo_factory)65 InfolistWindow::InfolistWindow(
66 TextRendererInterface *text_renderer,
67 DrawToolInterface *draw_tool,
68 GtkWrapperInterface *gtk,
69 CairoFactoryInterface *cairo_factory)
70 : GtkWindowBase(gtk),
71 text_renderer_(text_renderer),
72 style_(new RendererStyle()),
73 draw_tool_(draw_tool),
74 cairo_factory_(cairo_factory) {
75 mozc::renderer::RendererStyleHandler::GetRendererStyle(style_.get());
76 }
77
Update(const commands::Candidates & candidates)78 Size InfolistWindow::Update(const commands::Candidates &candidates) {
79 candidates_.CopyFrom(candidates);
80
81 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
82 const InformationList &usages = candidates_.usages();
83
84 int ypos = infostyle.window_border();
85 ypos += infostyle.caption_height();
86
87 for (int i = 0; i < usages.information_size(); ++i) {
88 ypos += GetRowRects(i, ypos).whole_rect.Height();
89 }
90 ypos += infostyle.window_border();
91
92 const Size result_size(style_->infolist_style().window_width(), ypos);
93 Resize(result_size);
94 Redraw();
95 return result_size;
96 }
97
98 // We do not use this function. So following code makes no sense.
GetCandidateColumnInClientCord() const99 Rect InfolistWindow::GetCandidateColumnInClientCord() const {
100 DCHECK(false) << "Do not call this function without CandidateWindow.";
101 return Rect(0, 0, 0, 0);
102 }
103
OnPaint(GtkWidget * widget,GdkEventExpose * event)104 bool InfolistWindow::OnPaint(GtkWidget *widget, GdkEventExpose *event) {
105 draw_tool_->Reset(cairo_factory_->CreateCairoInstance(
106 GetCanvasWidget()->window));
107 Draw();
108 return true;
109 }
110
DrawCaption()111 int InfolistWindow::DrawCaption() {
112 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
113 if (!infostyle.has_caption_string()) {
114 return 0;
115 }
116 const RendererStyle::TextStyle &caption_style = infostyle.caption_style();
117 const int caption_height = infostyle.caption_height();
118 const Rect background_rect(
119 infostyle.window_border(),
120 infostyle.window_border(),
121 infostyle.window_width() - infostyle.window_border() * 2,
122 caption_height);
123
124 const RGBA bgcolor = StyleColorToRGBA(infostyle.caption_background_color());
125 draw_tool_->FillRect(background_rect, bgcolor);
126
127 const Rect caption_rect(
128 background_rect.Left()
129 + infostyle.caption_padding() + caption_style.left_padding(),
130 background_rect.Top() + infostyle.caption_padding(),
131 background_rect.Width()
132 - infostyle.caption_padding() - caption_style.left_padding(),
133 caption_height - infostyle.caption_padding());
134 text_renderer_->RenderText(infostyle.caption_string(), caption_rect,
135 FontSpec::FONTSET_INFOLIST_CAPTION);
136 return infostyle.caption_height();
137 }
138
DrawFrame(int height)139 void InfolistWindow::DrawFrame(int height) {
140 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
141 const Rect rect(0, 0, infostyle.window_width(), height);
142 const RGBA framecolor = StyleColorToRGBA(infostyle.border_color());
143 draw_tool_->FrameRect(rect, framecolor, 1);
144 }
145
Draw()146 void InfolistWindow::Draw() {
147 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
148 const InformationList &usages = candidates_.usages();
149 int ypos = infostyle.window_border();
150 ypos += DrawCaption();
151 for (int i = 0; i < usages.information_size(); ++i) {
152 ypos += DrawRow(i, ypos);
153 }
154 DrawFrame(ypos);
155 }
156
GetRenderingRects(const renderer::RendererStyle::TextStyle & style,const string & text,FontSpec::FONT_TYPE font_type,int top,Rect * background_rect,Rect * textarea_rect)157 void InfolistWindow::GetRenderingRects(
158 const renderer::RendererStyle::TextStyle &style,
159 const string &text,
160 FontSpec::FONT_TYPE font_type,
161 int top,
162 Rect *background_rect,
163 Rect *textarea_rect) {
164 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
165 const int text_width = infostyle.window_width()
166 - style.left_padding() - style.right_padding()
167 - infostyle.window_border() * 2 - infostyle.row_rect_padding() * 2;
168
169 const Size text_size = text_renderer_->GetMultiLinePixelSize(font_type,
170 text,
171 text_width);
172
173 background_rect->origin.x = infostyle.window_border();
174 background_rect->origin.y = top;
175 background_rect->size.width =
176 infostyle.window_width() - infostyle.window_border() * 2;
177 background_rect->size.height =
178 text_size.height + infostyle.row_rect_padding() * 2;
179
180 *textarea_rect = *background_rect;
181
182 textarea_rect->origin.x +=
183 infostyle.row_rect_padding() + style.left_padding();
184 textarea_rect->origin.y += infostyle.row_rect_padding();
185 textarea_rect->size.width = text_width;
186 textarea_rect->size.height = text_size.height;
187 }
188
GetRowRects(int row,int ypos)189 InfolistWindow::RenderingRowRects InfolistWindow::GetRowRects(int row,
190 int ypos) {
191 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
192 const InformationList &usages = candidates_.usages();
193 const RendererStyle::TextStyle &title_style = infostyle.title_style();
194 const RendererStyle::TextStyle &desc_style = infostyle.description_style();
195 DCHECK_GT(usages.information_size(), row);
196 const Information &info = usages.information(row);
197
198 RenderingRowRects result;
199
200 GetRenderingRects(title_style,
201 info.title(),
202 FontSpec::FONTSET_INFOLIST_TITLE,
203 ypos,
204 &result.title_back_rect,
205 &result.title_rect);
206 ypos += result.title_back_rect.size.height;
207 GetRenderingRects(desc_style,
208 info.description(),
209 FontSpec::FONTSET_INFOLIST_DESCRIPTION,
210 ypos,
211 &result.desc_back_rect,
212 &result.desc_rect);
213 result.whole_rect = result.title_back_rect;
214 result.whole_rect.size.height += result.desc_back_rect.Height();
215 return result;
216 }
217
DrawRow(int row,int ypos)218 int InfolistWindow::DrawRow(int row, int ypos) {
219 const RendererStyle::InfolistStyle &infostyle = style_->infolist_style();
220 const InformationList &usages = candidates_.usages();
221 const RendererStyle::TextStyle &title_style = infostyle.title_style();
222 const RendererStyle::TextStyle &desc_style = infostyle.description_style();
223 DCHECK_GT(usages.information_size(), row);
224 const Information &info = usages.information(row);
225 const RenderingRowRects row_rects = GetRowRects(row, ypos);
226
227 if (usages.has_focused_index() && (row == usages.focused_index())) {
228 const RGBA bgcol = StyleColorToRGBA(infostyle.focused_background_color());
229 draw_tool_->FillRect(row_rects.whole_rect, bgcol);
230
231 const RGBA frcol = StyleColorToRGBA(infostyle.focused_border_color());
232 draw_tool_->FrameRect(row_rects.whole_rect, frcol, 1);
233 } else {
234 if (title_style.has_background_color()) {
235 draw_tool_->FillRect(row_rects.title_back_rect,
236 StyleColorToRGBA(title_style.background_color()));
237 } else {
238 draw_tool_->FillRect(row_rects.title_back_rect, kWhite);
239 }
240 if (desc_style.has_background_color()) {
241 draw_tool_->FillRect(row_rects.desc_back_rect,
242 StyleColorToRGBA(desc_style.background_color()));
243 } else {
244 draw_tool_->FillRect(row_rects.desc_back_rect, kWhite);
245 }
246 }
247
248 text_renderer_->RenderText(info.title(), row_rects.title_rect,
249 FontSpec::FONTSET_INFOLIST_TITLE);
250 text_renderer_->RenderText(info.description(), row_rects.desc_rect,
251 FontSpec::FONTSET_INFOLIST_DESCRIPTION);
252 return row_rects.whole_rect.Height();
253 }
254
Initialize()255 void InfolistWindow::Initialize() {
256 text_renderer_->Initialize(GetCanvasWidget()->window);
257 }
258
ReloadFontConfig(const string & font_description)259 void InfolistWindow::ReloadFontConfig(const string &font_description) {
260 text_renderer_->ReloadFontConfig(font_description);
261 }
262
263 } // namespace gtk
264 } // namespace renderer
265 } // namespace mozc
266