| 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 |