OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. 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 "pdf/thumbnail_control.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "pdf/draw_utils.h" | |
12 #include "pdf/number_image_generator.h" | |
13 | |
14 namespace chrome_pdf { | |
15 | |
16 const int kLeftBorderSize = 52; | |
17 const int kBorderSize = 12; | |
18 const int kHighlightBorderSize = 2; | |
19 | |
20 const uint32 kLeftColor = 0x003F537B; | |
21 const uint32 kRightColor = 0x990D1626; | |
22 | |
23 const uint32 kTopHighlightColor = 0xFF426DC9; | |
24 const uint32 kBottomHighlightColor = 0xFF6391DE; | |
25 const uint32 kThumbnailBackgroundColor = 0xFF000000; | |
26 | |
27 const uint32 kSlidingTimeoutMs = 50; | |
28 const int32 kSlidingShift = 50; | |
29 | |
30 const double kNonSelectedThumbnailAlpha = 0.91; | |
31 | |
32 ThumbnailControl::ThumbnailControl() | |
33 : engine_(NULL), sliding_width_(0), sliding_shift_(kSlidingShift), | |
34 sliding_timeout_(kSlidingTimeoutMs), sliding_timer_id_(0) { | |
35 } | |
36 | |
37 ThumbnailControl::~ThumbnailControl() { | |
38 ClearCache(); | |
39 } | |
40 | |
41 bool ThumbnailControl::CreateThumbnailControl( | |
42 uint32 id, const pp::Rect& rc, | |
43 bool visible, Owner* owner, PDFEngine* engine, | |
44 NumberImageGenerator* number_image_generator) { | |
45 engine_ = engine; | |
46 number_image_generator_ = number_image_generator; | |
47 sliding_width_ = rc.width(); | |
48 | |
49 return Control::Create(id, rc, visible, owner); | |
50 } | |
51 | |
52 void ThumbnailControl::SetPosition(int position, int total, bool invalidate) { | |
53 visible_rect_ = pp::Rect(); | |
54 visible_pages_.clear(); | |
55 | |
56 if (rect().width() < kLeftBorderSize + kBorderSize) { | |
57 return; // control is too narrow to show thumbnails. | |
58 } | |
59 | |
60 int num_pages = engine_->GetNumberOfPages(); | |
61 | |
62 int max_doc_width = 0, total_doc_height = 0; | |
63 std::vector<pp::Rect> page_sizes(num_pages); | |
64 for (int i = 0; i < num_pages; ++i) { | |
65 page_sizes[i] = engine_->GetPageRect(i); | |
66 max_doc_width = std::max(max_doc_width, page_sizes[i].width()); | |
67 total_doc_height += page_sizes[i].height(); | |
68 } | |
69 | |
70 if (!max_doc_width) | |
71 return; | |
72 | |
73 int max_thumbnail_width = rect().width() - kLeftBorderSize - kBorderSize; | |
74 double thumbnail_ratio = | |
75 max_thumbnail_width / static_cast<double>(max_doc_width); | |
76 | |
77 int total_thumbnail_height = 0; | |
78 for (int i = 0; i < num_pages; ++i) { | |
79 total_thumbnail_height += kBorderSize; | |
80 int thumbnail_width = | |
81 static_cast<int>(page_sizes[i].width() * thumbnail_ratio); | |
82 int thumbnail_height = | |
83 static_cast<int>(page_sizes[i].height() * thumbnail_ratio); | |
84 int x = (max_thumbnail_width - thumbnail_width) / 2; | |
85 page_sizes[i] = | |
86 pp::Rect(x, total_thumbnail_height, thumbnail_width, thumbnail_height); | |
87 total_thumbnail_height += thumbnail_height; | |
88 } | |
89 total_thumbnail_height += kBorderSize; | |
90 | |
91 int visible_y = 0; | |
92 if (total > 0) { | |
93 double range = total_thumbnail_height - rect().height(); | |
94 if (range < 0) | |
95 range = 0; | |
96 visible_y = static_cast<int>(range * position / total); | |
97 } | |
98 visible_rect_ = pp::Rect(0, visible_y, max_thumbnail_width, rect().height()); | |
99 | |
100 for (int i = 0; i < num_pages; ++i) { | |
101 if (page_sizes[i].Intersects(visible_rect_)) { | |
102 PageInfo page_info; | |
103 page_info.index = i; | |
104 page_info.rect = page_sizes[i]; | |
105 page_info.rect.Offset(kLeftBorderSize, -visible_rect_.y()); | |
106 visible_pages_.push_back(page_info); | |
107 } | |
108 } | |
109 | |
110 if (invalidate) | |
111 owner()->Invalidate(id(), rect()); | |
112 } | |
113 | |
114 void ThumbnailControl::Show(bool visible, bool invalidate) { | |
115 if (!visible || invalidate) | |
116 ClearCache(); | |
117 sliding_width_ = rect().width(); | |
118 Control::Show(visible, invalidate); | |
119 } | |
120 | |
121 void ThumbnailControl::SlideIn() { | |
122 if (visible()) | |
123 return; | |
124 | |
125 Show(true, false); | |
126 sliding_width_ = 0; | |
127 sliding_shift_ = kSlidingShift; | |
128 | |
129 sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_); | |
130 owner()->Invalidate(id(), rect()); | |
131 } | |
132 | |
133 void ThumbnailControl::SlideOut() { | |
134 if (!visible()) | |
135 return; | |
136 sliding_shift_ = -kSlidingShift; | |
137 sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_); | |
138 } | |
139 | |
140 void ThumbnailControl::Paint(pp::ImageData* image_data, const pp::Rect& rc) { | |
141 if (!visible()) | |
142 return; | |
143 | |
144 pp::Rect control_rc(rect()); | |
145 control_rc.Offset(control_rc.width() - sliding_width_, 0); | |
146 control_rc.set_width(sliding_width_); | |
147 | |
148 pp::Rect draw_rc = rc.Intersect(control_rc); | |
149 if (draw_rc.IsEmpty()) | |
150 return; | |
151 | |
152 pp::Rect gradient_rc(control_rc.x(), draw_rc.y(), | |
153 control_rc.width(), draw_rc.height()); | |
154 GradientFill(owner()->GetInstance(), | |
155 image_data, | |
156 draw_rc, | |
157 gradient_rc, | |
158 kLeftColor, | |
159 kRightColor, | |
160 true, | |
161 transparency()); | |
162 | |
163 int selected_page = engine_->GetMostVisiblePage(); | |
164 for (size_t i = 0; i < visible_pages_.size(); ++i) { | |
165 pp::Rect page_rc = visible_pages_[i].rect; | |
166 page_rc.Offset(control_rc.point()); | |
167 | |
168 if (visible_pages_[i].index == selected_page) { | |
169 pp::Rect highlight_rc = page_rc; | |
170 highlight_rc.Inset(-kHighlightBorderSize, -kHighlightBorderSize); | |
171 GradientFill(owner()->GetInstance(), | |
172 image_data, | |
173 draw_rc, | |
174 highlight_rc, | |
175 kTopHighlightColor, | |
176 kBottomHighlightColor, | |
177 false, | |
178 transparency()); | |
179 } | |
180 | |
181 pp::Rect draw_page_rc = page_rc.Intersect(draw_rc); | |
182 if (draw_page_rc.IsEmpty()) | |
183 continue; | |
184 | |
185 // First search page image in the cache. | |
186 pp::ImageData* thumbnail = NULL; | |
187 std::map<int, pp::ImageData*>::iterator it = | |
188 image_cache_.find(visible_pages_[i].index); | |
189 if (it != image_cache_.end()) { | |
190 if (it->second->size() == page_rc.size()) | |
191 thumbnail = image_cache_[visible_pages_[i].index]; | |
192 else | |
193 image_cache_.erase(it); | |
194 } | |
195 | |
196 // If page is not found in the cache, create new one. | |
197 if (thumbnail == NULL) { | |
198 thumbnail = new pp::ImageData(owner()->GetInstance(), | |
199 PP_IMAGEDATAFORMAT_BGRA_PREMUL, | |
200 page_rc.size(), | |
201 false); | |
202 engine_->PaintThumbnail(thumbnail, visible_pages_[i].index); | |
203 | |
204 pp::ImageData page_number; | |
205 number_image_generator_->GenerateImage( | |
206 visible_pages_[i].index + 1, &page_number); | |
207 pp::Point origin( | |
208 (thumbnail->size().width() - page_number.size().width()) / 2, | |
209 (thumbnail->size().height() - page_number.size().height()) / 2); | |
210 | |
211 if (origin.x() > 0 && origin.y() > 0) { | |
212 AlphaBlend(page_number, pp::Rect(pp::Point(), page_number.size()), | |
213 thumbnail, origin, kOpaqueAlpha); | |
214 } | |
215 | |
216 image_cache_[visible_pages_[i].index] = thumbnail; | |
217 } | |
218 | |
219 uint8 alpha = transparency(); | |
220 if (visible_pages_[i].index != selected_page) | |
221 alpha = static_cast<uint8>(alpha * kNonSelectedThumbnailAlpha); | |
222 FillRect(image_data, draw_page_rc, kThumbnailBackgroundColor); | |
223 draw_page_rc.Offset(-page_rc.x(), -page_rc.y()); | |
224 AlphaBlend(*thumbnail, draw_page_rc, image_data, | |
225 draw_page_rc.point() + page_rc.point(), alpha); | |
226 } | |
227 } | |
228 | |
229 bool ThumbnailControl::HandleEvent(const pp::InputEvent& event) { | |
230 if (!visible()) | |
231 return false; | |
232 | |
233 pp::MouseInputEvent mouse_event(event); | |
234 if (mouse_event.is_null()) | |
235 return false; | |
236 pp::Point pt = mouse_event.GetPosition(); | |
237 if (!rect().Contains(pt)) | |
238 return false; | |
239 | |
240 int over_page = -1; | |
241 for (size_t i = 0; i < visible_pages_.size(); ++i) { | |
242 pp::Rect page_rc = visible_pages_[i].rect; | |
243 page_rc.Offset(rect().point()); | |
244 if (page_rc.Contains(pt)) { | |
245 over_page = i; | |
246 break; | |
247 } | |
248 } | |
249 | |
250 bool handled = false; | |
251 switch (event.GetType()) { | |
252 case PP_INPUTEVENT_TYPE_MOUSEMOVE: | |
253 owner()->SetCursor(id(), | |
254 over_page == -1 ? PP_CURSORTYPE_POINTER : PP_CURSORTYPE_HAND); | |
255 break; | |
256 case PP_INPUTEVENT_TYPE_MOUSEDOWN: | |
257 if (over_page != -1) { | |
258 owner()->Invalidate(id(), rect()); | |
259 owner()->OnEvent(id(), EVENT_ID_THUMBNAIL_SELECTED, | |
260 &visible_pages_[over_page].index); | |
261 } | |
262 handled = true; | |
263 break; | |
264 default: | |
265 break; | |
266 } | |
267 | |
268 return handled; | |
269 } | |
270 | |
271 void ThumbnailControl::OnTimerFired(uint32 timer_id) { | |
272 if (timer_id == sliding_timer_id_) { | |
273 sliding_width_ += sliding_shift_; | |
274 if (sliding_width_ <= 0) { | |
275 // We completely slided out. Make control invisible now. | |
276 Show(false, false); | |
277 } else if (sliding_width_ >= rect().width()) { | |
278 // We completely slided in. Make sliding width to full control width. | |
279 sliding_width_ = rect().width(); | |
280 } else { | |
281 // We have not completed sliding yet. Keep sliding. | |
282 sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_); | |
283 } | |
284 owner()->Invalidate(id(), rect()); | |
285 } | |
286 } | |
287 | |
288 void ThumbnailControl::ResetEngine(PDFEngine* engine) { | |
289 engine_ = engine; | |
290 ClearCache(); | |
291 } | |
292 | |
293 void ThumbnailControl::ClearCache() { | |
294 std::map<int, pp::ImageData*>::iterator it; | |
295 for (it = image_cache_.begin(); it != image_cache_.end(); ++it) { | |
296 delete it->second; | |
297 } | |
298 image_cache_.clear(); | |
299 } | |
300 | |
301 } // namespace chrome_pdf | |
OLD | NEW |