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

Side by Side Diff: chrome/browser/aeropeek_manager.cc

Issue 303033: Implements AeroPeek of Windows 7.. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/aeropeek_manager.h ('k') | chrome/browser/views/frame/browser_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 "chrome/browser/aeropeek_manager.h"
6
7 #include <dwmapi.h>
8 #include <shobjidl.h>
9
10 #include "app/gfx/gdi_util.h"
11 #include "app/gfx/icon_util.h"
12 #include "app/gfx/insets.h"
13 #include "app/win_util.h"
14 #include "app/win/window_impl.h"
15 #include "base/command_line.h"
16 #include "base/scoped_comptr_win.h"
17 #include "base/scoped_handle_win.h"
18 #include "base/scoped_native_library.h"
19 #include "base/win_util.h"
20 #include "chrome/app/chrome_dll_resource.h"
21 #include "chrome/browser/browser_list.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_thread.h"
24 #include "chrome/browser/renderer_host/backing_store.h"
25 #include "chrome/browser/renderer_host/render_view_host.h"
26 #include "chrome/browser/tab_contents/tab_contents.h"
27 #include "chrome/browser/tab_contents/tab_contents_delegate.h"
28 #include "chrome/browser/tab_contents/tab_contents_view.h"
29 #include "chrome/browser/tab_contents/thumbnail_generator.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "skia/ext/image_operations.h"
33 #include "skia/ext/platform_canvas.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35
36 namespace {
37
38 // Macros and COM interfaces used in this file.
39 // These interface declarations are copied from Windows SDK 7.
40 // TODO(hbono): Bug 16903: to be deleted when we use Windows SDK 7.
41
42 // Windows SDK 7 defines these macros only when _WIN32_WINNT >= 0x0601.
43 // Since Chrome currently sets _WIN32_WINNT to 0x0600, copy these defines here
44 // so we can use them.
45 #ifndef WM_DWMSENDICONICTHUMBNAIL
46 #define WM_DWMSENDICONICTHUMBNAIL 0x0323
47 #endif
48 #ifndef WM_DWMSENDICONICLIVEPREVIEWBITMAP
49 #define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
50 #endif
51
52 // COM interfaces defined only in Windows SDK 7.
53 #ifndef __ITaskbarList2_INTERFACE_DEFINED__
54 #define __ITaskbarList2_INTERFACE_DEFINED__
55
56 // EXTERN_C const IID IID_ITaskbarList2;
57 MIDL_INTERFACE("602D4995-B13A-429b-A66E-1935E44F4317")
58 ITaskbarList2 : public ITaskbarList {
59 public:
60 virtual HRESULT STDMETHODCALLTYPE MarkFullscreenWindow(
61 /* [in] */ __RPC__in HWND hwnd,
62 /* [in] */ BOOL fFullscreen) = 0;
63 };
64
65 #endif /* __ITaskbarList2_INTERFACE_DEFINED__ */
66
67 #ifndef __ITaskbarList3_INTERFACE_DEFINED__
68 #define __ITaskbarList3_INTERFACE_DEFINED__
69
70 typedef struct tagTHUMBBUTTON {
71 DWORD dwMask;
72 UINT iId;
73 UINT iBitmap;
74 HICON hIcon;
75 WCHAR szTip[ 260 ];
76 DWORD dwFlags;
77 } THUMBBUTTON;
78
79 typedef struct tagTHUMBBUTTON *LPTHUMBBUTTON;
80
81 // THUMBBUTTON flags
82 #define THBF_ENABLED 0x0000
83 #define THBF_DISABLED 0x0001
84 #define THBF_DISMISSONCLICK 0x0002
85 #define THBF_NOBACKGROUND 0x0004
86 #define THBF_HIDDEN 0x0008
87 // THUMBBUTTON mask
88 #define THB_BITMAP 0x0001
89 #define THB_ICON 0x0002
90 #define THB_TOOLTIP 0x0004
91 #define THB_FLAGS 0x0008
92 #define THBN_CLICKED 0x1800
93
94 typedef /* [v1_enum] */ enum TBPFLAG {
95 TBPF_NOPROGRESS = 0,
96 TBPF_INDETERMINATE = 0x1,
97 TBPF_NORMAL = 0x2,
98 TBPF_ERROR = 0x4,
99 TBPF_PAUSED = 0x8
100 } TBPFLAG;
101
102 // EXTERN_C const IID IID_ITaskbarList3;
103
104 MIDL_INTERFACE("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")
105 ITaskbarList3 : public ITaskbarList2 {
106 public:
107 virtual HRESULT STDMETHODCALLTYPE SetProgressValue(
108 /* [in] */ __RPC__in HWND hwnd,
109 /* [in] */ ULONGLONG ullCompleted,
110 /* [in] */ ULONGLONG ullTotal) = 0;
111 virtual HRESULT STDMETHODCALLTYPE SetProgressState(
112 /* [in] */ __RPC__in HWND hwnd,
113 /* [in] */ TBPFLAG tbpFlags) = 0;
114 virtual HRESULT STDMETHODCALLTYPE RegisterTab(
115 /* [in] */ __RPC__in HWND hwndTab,
116 /* [in] */ __RPC__in HWND hwndMDI) = 0;
117 virtual HRESULT STDMETHODCALLTYPE UnregisterTab(
118 /* [in] */ __RPC__in HWND hwndTab) = 0;
119 virtual HRESULT STDMETHODCALLTYPE SetTabOrder(
120 /* [in] */ __RPC__in HWND hwndTab,
121 /* [in] */ __RPC__in HWND hwndInsertBefore) = 0;
122 virtual HRESULT STDMETHODCALLTYPE SetTabActive(
123 /* [in] */ __RPC__in HWND hwndTab,
124 /* [in] */ __RPC__in HWND hwndMDI,
125 /* [in] */ DWORD dwReserved) = 0;
126 virtual HRESULT STDMETHODCALLTYPE ThumbBarAddButtons(
127 /* [in] */ __RPC__in HWND hwnd,
128 /* [in] */ UINT cButtons,
129 /* [size_is][in] */ __RPC__in_ecount_full(cButtons)
130 LPTHUMBBUTTON pButton) = 0;
131 virtual HRESULT STDMETHODCALLTYPE ThumbBarUpdateButtons(
132 /* [in] */ __RPC__in HWND hwnd,
133 /* [in] */ UINT cButtons,
134 /* [size_is][in] */ __RPC__in_ecount_full(cButtons)
135 LPTHUMBBUTTON pButton) = 0;
136 virtual HRESULT STDMETHODCALLTYPE ThumbBarSetImageList(
137 /* [in] */ __RPC__in HWND hwnd,
138 /* [in] */ __RPC__in_opt HIMAGELIST himl) = 0;
139 virtual HRESULT STDMETHODCALLTYPE SetOverlayIcon(
140 /* [in] */ __RPC__in HWND hwnd,
141 /* [in] */ __RPC__in HICON hIcon,
142 /* [string][in] */ __RPC__in_string LPCWSTR pszDescription) = 0;
143 virtual HRESULT STDMETHODCALLTYPE SetThumbnailTooltip(
144 /* [in] */ __RPC__in HWND hwnd,
145 /* [string][in] */ __RPC__in_string LPCWSTR pszTip) = 0;
146 virtual HRESULT STDMETHODCALLTYPE SetThumbnailClip(
147 /* [in] */ __RPC__in HWND hwnd,
148 /* [in] */ __RPC__in RECT *prcClip) = 0;
149 };
150 #endif // __ITaskbarList3_INTERFACE_DEFINED__
151
152 // END OF WINDOWS SDK 7.0
153
154 } // namespace
155
156 namespace {
157
158 // Sends a thumbnail bitmap to Windows. Windows assumes this function is called
159 // in response to a WM_DWMSENDICONICTHUMBNAIL message sent to a place-holder
160 // window. We need to call DwmInvalidateIconicBitmap() to force Windows to send
161 // the message.
162 HRESULT CallDwmSetIconicThumbnail(HWND window, HBITMAP bitmap, DWORD flags) {
163 FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi"));
164 base::ScopedNativeLibrary dwmapi(dwmapi_path);
165
166 typedef HRESULT (STDAPICALLTYPE *DwmSetIconicThumbnailProc)(
167 HWND, HBITMAP, DWORD);
168 DwmSetIconicThumbnailProc dwm_set_iconic_thumbnail =
169 static_cast<DwmSetIconicThumbnailProc>(
170 dwmapi.GetFunctionPointer("DwmSetIconicThumbnail"));
171
172 if (!dwm_set_iconic_thumbnail)
173 return E_FAIL;
174
175 return dwm_set_iconic_thumbnail(window, bitmap, flags);
176 }
177
178 // Sends a preview bitmap to Windows. Windows assumes this function is called in
179 // response to a WM_DWMSENDICONICLIVEPREVIEWBITMAP message sent to a
180 // place-holder window. (Windows doesn't provide any function that forces
181 // Windows to send the message.
182 HRESULT CallDwmSetIconicLivePreviewBitmap(HWND window,
183 HBITMAP bitmap,
184 POINT* client,
185 DWORD flags) {
186 FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi"));
187 base::ScopedNativeLibrary dwmapi(dwmapi_path);
188
189 typedef HRESULT (STDAPICALLTYPE *DwmSetIconicLivePreviewBitmapProc)(
190 HWND, HBITMAP, POINT*, DWORD);
191 DwmSetIconicLivePreviewBitmapProc dwm_set_live_preview_bitmap =
192 static_cast<DwmSetIconicLivePreviewBitmapProc>(
193 dwmapi.GetFunctionPointer("DwmSetIconicLivePreviewBitmap"));
194
195 if (!dwm_set_live_preview_bitmap)
196 return E_FAIL;
197
198 return dwm_set_live_preview_bitmap(window, bitmap, client, flags);
199 }
200
201 // Invalidates the thumbnail image of the specified place-holder window. (See
202 // the comments in CallDwmSetIconicThumbnai()).
203 HRESULT CallDwmInvalidateIconicBitmaps(HWND window) {
204 FilePath dwmapi_path(base::GetNativeLibraryName(L"dwmapi"));
205 base::ScopedNativeLibrary dwmapi(dwmapi_path);
206
207 typedef HRESULT (STDAPICALLTYPE *DwmInvalidateIconicBitmapsProc)(HWND);
208 DwmInvalidateIconicBitmapsProc dwm_invalidate_iconic_bitmaps =
209 static_cast<DwmInvalidateIconicBitmapsProc>(
210 dwmapi.GetFunctionPointer("DwmInvalidateIconicBitmaps"));
211
212 if (!dwm_invalidate_iconic_bitmaps)
213 return E_FAIL;
214
215 return dwm_invalidate_iconic_bitmaps(window);
216 }
217
218 } // namespace
219
220 namespace {
221
222 // Tasks used in this file.
223 // This file uses three I/O tasks to implement AeroPeek:
224 // * RegisterThumbnailTask
225 // Register a tab into the thumbnail list of Windows.
226 // * SendThumbnailTask
227 // Create a thumbnail image and send it to Windows.
228 // * SendLivePreviewTask
229 // Create a preview image and send it to Windows.
230 // These I/O tasks indirectly access the specified tab through the
231 // AeroPeekWindowDelegate interface to prevent these tasks from accessing the
232 // deleted tabs.
233
234 // A task that registers a thumbnail window as a child of the specified
235 // browser application.
236 class RegisterThumbnailTask : public Task {
237 public:
238 RegisterThumbnailTask(HWND frame_window, HWND window, bool active)
239 : frame_window_(frame_window),
240 window_(window),
241 active_(active) {
242 }
243
244 private:
245 void Run() {
246 // Set the App ID of the browser for this place-holder window to tell
247 // that this window is a child of the browser application, i.e. to tell
248 // that this thumbnail window should be displayed when we hover the
249 // browser icon in the taskbar.
250 win_util::SetAppIdForWindow(chrome::kBrowserAppID, window_);
251
252 // Register this place-holder window to the taskbar as a child of
253 // the browser window and add it to the end of its tab list.
254 // Correctly, this registration should be called after this browser window
255 // receives a registered window message "TaskbarButtonCreated", which
256 // means that Windows creates a taskbar button for this window in its
257 // taskbar. But it seems to be OK to register it without checking the
258 // message.
259 // TODO(hbono): we need to check this registered message?
260 ScopedComPtr<ITaskbarList3> taskbar;
261 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
262 CLSCTX_INPROC_SERVER);
263 if (FAILED(result)) {
264 LOG(INFO) << "failed creating a TaskbarList object: " << result;
265 return;
266 }
267
268 result = taskbar->HrInit();
269 if (FAILED(result)) {
270 LOG(INFO) << "failed initializing a TaskbarList obejct: " << result;
271 return;
272 }
273
274 result = taskbar->RegisterTab(window_, frame_window_);
275 if (FAILED(result)) {
276 LOG(INFO) << "failed registering a thumbnail window: " << result;
277 return;
278 }
279
280 result = taskbar->SetTabOrder(window_, NULL);
281 if (FAILED(result)) {
282 LOG(INFO) << "failed adding a thumbnail window: " << result;
283 return;
284 }
285
286 if (active_) {
287 result = taskbar->SetTabActive(window_, frame_window_, 0);
288 if (FAILED(result))
289 LOG(INFO) << "failed activating a thumbnail window: " << result;
290 }
291 }
292
293 private:
294 // An application window to which we are going to register a tab window.
295 // This "application window" is a browser frame in terms of Chrome.
296 HWND frame_window_;
297
298 // A tab window.
299 // After we register this window as a child of the above application window,
300 // Windows sends AeroPeek events to this window.
301 // It seems this window MUST be a tool window.
302 HWND window_;
303
304 // Whether or not we need to activate this tab by default.
305 bool active_;
306 };
307
308 // A task which creates a thumbnail image used by AeroPeek and sends it to
309 // Windows.
310 class SendThumbnailTask : public Task {
311 public:
312 SendThumbnailTask(HWND aeropeek_window,
313 const gfx::Rect& content_bounds,
314 const gfx::Size& aeropeek_size,
315 const SkBitmap& tab_bitmap,
316 base::WaitableEvent* ready)
317 : aeropeek_window_(aeropeek_window),
318 content_bounds_(content_bounds),
319 aeropeek_size_(aeropeek_size),
320 tab_bitmap_(tab_bitmap),
321 ready_(ready) {
322 }
323
324 ~SendThumbnailTask() {
325 if (ready_)
326 ready_->Signal();
327 }
328
329 private:
330 void Run() {
331 // Calculate the size of the aeropeek thumbnail and resize the tab bitmap
332 // to the size. When the given bitmap is an empty bitmap, we create a dummy
333 // bitmap from the content-area rectangle to create a DIB. (We don't need to
334 // allocate pixels for this case since we don't use them.)
335 gfx::Size thumbnail_size;
336 SkBitmap thumbnail_bitmap;
337
338 if (tab_bitmap_.isNull() || tab_bitmap_.empty()) {
339 GetThumbnailSize(content_bounds_.width(), content_bounds_.height(),
340 &thumbnail_size);
341
342 thumbnail_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
343 thumbnail_size.width(),
344 thumbnail_size.height());
345 } else {
346 GetThumbnailSize(tab_bitmap_.width(), tab_bitmap_.height(),
347 &thumbnail_size);
348
349 thumbnail_bitmap = skia::ImageOperations::Resize(
350 tab_bitmap_,
351 skia::ImageOperations::RESIZE_LANCZOS3,
352 thumbnail_size.width(),
353 thumbnail_size.height());
354 }
355
356 // Create a DIB, copy the resized image, and send the DIB to Windows.
357 // We can delete this DIB after sending it to Windows since Windows creates
358 // a copy of the DIB and use it.
359 ScopedHDC hdc(CreateCompatibleDC(NULL));
360 if (!hdc.Get()) {
361 LOG(ERROR) << "cannot create a memory DC: " << GetLastError();
362 return;
363 }
364
365 BITMAPINFOHEADER header;
366 gfx::CreateBitmapHeader(thumbnail_size.width(), thumbnail_size.height(),
367 &header);
368
369 void* bitmap_data = NULL;
370 ScopedBitmap bitmap(CreateDIBSection(hdc,
371 reinterpret_cast<BITMAPINFO*>(&header),
372 DIB_RGB_COLORS,
373 &bitmap_data,
374 NULL,
375 0));
376
377 if (!bitmap.Get() || !bitmap_data) {
378 LOG(ERROR) << "cannot create a bitmap: " << GetLastError();
379 return;
380 }
381
382 SkAutoLockPixels lock(thumbnail_bitmap);
383 int* content_pixels = reinterpret_cast<int*>(bitmap_data);
384 for (int y = 0; y < thumbnail_size.height(); ++y) {
385 for (int x = 0; x < thumbnail_size.width(); ++x) {
386 content_pixels[y * thumbnail_size.width() + x] =
387 GetPixel(thumbnail_bitmap, x, y);
388 }
389 }
390
391 HRESULT result = CallDwmSetIconicThumbnail(aeropeek_window_, bitmap, 0);
392 if (FAILED(result))
393 LOG(ERROR) << "cannot set a tab thumbnail: " << result;
394 }
395
396 // Calculates the thumbnail size sent to Windows so we can preserve the pixel
397 // aspect-ratio of the source bitmap. Since Windows returns an error when we
398 // send an image bigger than the given size, we decrease either the thumbnail
399 // width or the thumbnail height so we can fit the longer edge of the source
400 // window.
401 void GetThumbnailSize(int width, int height, gfx::Size* output) const {
402 float thumbnail_width = static_cast<float>(aeropeek_size_.width());
403 float thumbnail_height = static_cast<float>(aeropeek_size_.height());
404 float source_width = static_cast<float>(width);
405 float source_height = static_cast<float>(height);
406 DCHECK(source_width && source_height);
407
408 float ratio_width = thumbnail_width / source_width;
409 float ratio_height = thumbnail_height / source_height;
410 if (ratio_width > ratio_height) {
411 thumbnail_width = source_width * ratio_height;
412 } else {
413 thumbnail_height = source_height * ratio_width;
414 }
415
416 output->set_width(static_cast<int>(thumbnail_width));
417 output->set_height(static_cast<int>(thumbnail_height));
418 }
419
420 // Returns a pixel of the specified bitmap. If this bitmap is a dummy bitmap,
421 // this function returns an opaque white pixel instead.
422 int GetPixel(const SkBitmap& bitmap, int x, int y) const {
423 const int* tab_pixels = reinterpret_cast<const int*>(bitmap.getPixels());
424 if (!tab_pixels)
425 return 0xFFFFFFFF;
426 return tab_pixels[y * bitmap.width() + x];
427 }
428
429 private:
430 // A window handle to the place-holder window used by AeroPeek.
431 HWND aeropeek_window_;
432
433 // The bounding rectangle of the user-perceived content area.
434 // This rectangle is used only for creating a fall-back bitmap.
435 gfx::Rect content_bounds_;
436
437 // The size of an output image to be sent to Windows.
438 gfx::Size aeropeek_size_;
439
440 // The source bitmap.
441 SkBitmap tab_bitmap_;
442
443 // An event to notify when this task finishes.
444 base::WaitableEvent* ready_;
445 };
446
447 // A task which creates a preview image used by AeroPeek and sends it to
448 // Windows.
449 // This task becomes more complicated than SendThumbnailTask because this task
450 // calculates the rectangle of the user-perceived content area (infobars +
451 // content area) so Windows can paste the preview image on it.
452 // This task is used if an AeroPeek window receives a
453 // WM_DWMSENDICONICLIVEPREVIEWBITMAP message.
454 class SendLivePreviewTask : public Task {
455 public:
456 SendLivePreviewTask(HWND aeropeek_window,
457 const gfx::Rect& content_bounds,
458 const SkBitmap& tab_bitmap)
459 : aeropeek_window_(aeropeek_window),
460 content_bounds_(content_bounds),
461 tab_bitmap_(tab_bitmap) {
462 }
463
464 ~SendLivePreviewTask() {
465 }
466
467 private:
468 void Run() {
469 // Create a DIB for the user-perceived content area of the tab, copy the
470 // tab image into the DIB, and send it to Windows.
471 // We don't need to paste this tab image onto the frame image since Windows
472 // automatically pastes it for us.
473 ScopedHDC hdc(CreateCompatibleDC(NULL));
474 if (!hdc.Get()) {
475 LOG(ERROR) << "cannot create a memory DC: " << GetLastError();
476 return;
477 }
478
479 BITMAPINFOHEADER header;
480 gfx::CreateBitmapHeader(content_bounds_.width(), content_bounds_.height(),
481 &header);
482
483 void* bitmap_data = NULL;
484 ScopedBitmap bitmap(CreateDIBSection(hdc.Get(),
485 reinterpret_cast<BITMAPINFO*>(&header),
486 DIB_RGB_COLORS, &bitmap_data,
487 NULL, 0));
488 if (!bitmap.Get() || !bitmap_data) {
489 LOG(ERROR) << "cannot create a bitmap: " << GetLastError();
490 return;
491 }
492
493 // Copy the tab image onto the DIB.
494 SkAutoLockPixels lock(tab_bitmap_);
495 int* content_pixels = reinterpret_cast<int*>(bitmap_data);
496 for (int y = 0; y < content_bounds_.height(); ++y) {
497 for (int x = 0; x < content_bounds_.width(); ++x)
498 content_pixels[y * content_bounds_.width() + x] = GetTabPixel(x, y);
499 }
500
501 // Send the preview image to Windows.
502 // We can set its offset to the top left corner of the user-perceived
503 // content area so Windows can paste this bitmap onto the correct
504 // position.
505 POINT content_offset = {content_bounds_.x(), content_bounds_.y()};
506 HRESULT result = CallDwmSetIconicLivePreviewBitmap(
507 aeropeek_window_, bitmap, &content_offset, 0);
508 if (FAILED(result))
509 LOG(ERROR) << "cannot send a content image: " << result;
510 }
511
512 int GetTabPixel(int x, int y) const {
513 // Return the opaque while pixel to prevent old foreground tab from being
514 // shown when we cannot get the specified pixel.
515 const int* tab_pixels = reinterpret_cast<int*>(tab_bitmap_.getPixels());
516 if (!tab_pixels || x >= tab_bitmap_.width() || y >= tab_bitmap_.height())
517 return 0xFFFFFFFF;
518
519 // DWM uses alpha values to distinguish opaque colors and transparent ones.
520 // Set the alpha value of this source pixel to prevent the original window
521 // from being shown through.
522 return 0xFF000000 | tab_pixels[y * tab_bitmap_.width() + x];
523 }
524
525 private:
526 // A window handle to the AeroPeek window.
527 HWND aeropeek_window_;
528
529 // The bounding rectangle of the user-perceived content area. When a tab
530 // hasn't been rendered since a browser window is resized, this size doesn't
531 // become the same as the bitmap size as shown below.
532 // +----------------------+
533 // | frame window |
534 // | +---------------------+
535 // | | tab contents |
536 // | +---------------------+
537 // | | old tab contents | |
538 // | +------------------+ |
539 // +----------------------+
540 // This rectangle is used for clipping the width and height of the bitmap and
541 // cleaning the old tab contents.
542 // +----------------------+
543 // | frame window |
544 // | +------------------+ |
545 // | | tab contents | |
546 // | +------------------+ |
547 // | | blank | |
548 // | +------------------+ |
549 // +----------------------+
550 gfx::Rect content_bounds_;
551
552 // The bitmap of the source tab.
553 SkBitmap tab_bitmap_;
554 };
555
556 } // namespace
557
558 // A class which implements a place-holder window used by AeroPeek.
559 // The major work of this class are:
560 // * Updating the status of Tab Thumbnails;
561 // * Receiving messages from Windows, and;
562 // * Translating received messages for TabStrip.
563 // This class is used by the AeroPeekManager class, which is a proxy
564 // between TabStrip and Windows 7.
565 class AeroPeekWindow : public app::WindowImpl {
566 public:
567 AeroPeekWindow(HWND frame_window,
568 AeroPeekWindowDelegate* delegate,
569 int tab_id,
570 bool tab_active,
571 const std::wstring& title,
572 const SkBitmap& favicon_bitmap);
573 ~AeroPeekWindow();
574
575 // Activates or deactivates this window.
576 // This window uses this information not only for highlighting the selected
577 // tab when Windows shows the thumbnail list, but also for preventing us
578 // from rendering AeroPeek images for deactivated windows so often.
579 void Activate();
580 void Deactivate();
581
582 // Updates the image of this window.
583 // When the AeroPeekManager class calls this function, this window starts
584 // a task which updates its thumbnail image.
585 // NOTE: to prevent sending lots of tasks that update the thumbnail images
586 // and hurt the system performance, we post a task only when |is_loading| is
587 // false for non-active tabs. (On the other hand, we always post an update
588 // task for an active tab as IE8 does.)
589 void Update(bool is_loading);
590
591 // Destroys this window.
592 // This function removes this window from the thumbnail list and deletes
593 // all the resources attached to this window, i.e. this object is not valid
594 // any longer after calling this function.
595 void Destroy();
596
597 // Updates the title of this window.
598 // This function just sends a WM_SETTEXT message to update the window title.
599 void SetTitle(const std::wstring& title);
600
601 // Updates the icon used for AeroPeek. Unlike SetTitle(), this function just
602 // saves a copy of the given bitmap since it takes time to create a Windows
603 // icon from this bitmap set it as the window icon. We will create a Windows
604 // when Windows sends a WM_GETICON message to retrieve it.
605 void SetFavIcon(const SkBitmap& favicon);
606
607 // Returns the tab ID associated with this window.
608 int tab_id() { return tab_id_; }
609
610 // Message handlers.
611 BEGIN_MSG_MAP_EX(TabbedThumbnailWindow)
612 MESSAGE_HANDLER_EX(WM_DWMSENDICONICTHUMBNAIL, OnDwmSendIconicThumbnail)
613 MESSAGE_HANDLER_EX(WM_DWMSENDICONICLIVEPREVIEWBITMAP,
614 OnDwmSendIconicLivePreviewBitmap)
615
616 MSG_WM_ACTIVATE(OnActivate)
617 MSG_WM_CLOSE(OnClose)
618 MSG_WM_CREATE(OnCreate)
619 MSG_WM_GETICON(OnGetIcon)
620 END_MSG_MAP()
621
622 private:
623 // Updates the thumbnail image of this window.
624 // This function is a wrapper function of CallDwmInvalidateIconicBitmaps()
625 // but it invalidates the thumbnail only when |ready_| is signaled to prevent
626 // us from posting two or more tasks.
627 void UpdateThumbnail();
628
629 // Returns the user-perceived content area.
630 gfx::Rect GetContentBounds() const;
631
632 // Message-handler functions.
633 // Called when a window has been created.
634 LRESULT OnCreate(LPCREATESTRUCT create_struct);
635
636 // Called when this thumbnail window is activated, i.e. a user clicks this
637 // thumbnail window.
638 void OnActivate(UINT action, BOOL minimized, HWND window);
639
640 // Called when this thumbnail window is closed, i.e. a user clicks the close
641 // button of this thumbnail window.
642 void OnClose();
643
644 // Called when Windows needs a thumbnail image for this thumbnail window.
645 // Windows can send a WM_DWMSENDICONICTHUMBNAIL message anytime when it
646 // needs the thumbnail bitmap for this place-holder window (e.g. when we
647 // register this place-holder window to Windows, etc.)
648 // When this window receives a WM_DWMSENDICONICTHUMBNAIL message, it HAS TO
649 // create a thumbnail bitmap and send it to Windows through a
650 // DwmSendIconicThumbnail() call. (Windows shows a "page-loading" animation
651 // while it waits for a thumbnail bitmap.)
652 LRESULT OnDwmSendIconicThumbnail(UINT message,
653 WPARAM wparam,
654 LPARAM lparam);
655
656 // Called when Windows needs a preview image for this thumbnail window.
657 // Same as above, Windows can send a WM_DWMSENDICONICLIVEPREVIEWBITMAP
658 // message anytime when it needs a preview bitmap and we have to create and
659 // send the bitmap when it needs it.
660 LRESULT OnDwmSendIconicLivePreviewBitmap(UINT message,
661 WPARAM wparam,
662 LPARAM lparam);
663
664 // Called when Windows needs an icon for this thumbnail window.
665 // Windows sends a WM_GETICON message with ICON_SMALL when it needs an
666 // AeroPeek icon. we handle WM_GETICON messages by ourselves so we can create
667 // a custom icon from a favicon only when Windows need it.
668 HICON OnGetIcon(UINT index);
669
670 private:
671 // An application window which owns this tab.
672 // We show this thumbnail image of this window when a user hovers a mouse
673 // cursor onto the taskbar icon of this application window.
674 HWND frame_window_;
675
676 // An interface which dispatches events received from Window.
677 // This window notifies events received from Windows to TabStrip through
678 // this interface.
679 // We should not directly access TabContents members since Windows may send
680 // AeroPeek events to a tab closed by Chrome.
681 // To prevent such race condition, we get access to TabContents through
682 // AeroPeekManager.
683 AeroPeekWindowDelegate* delegate_;
684
685 // A tab ID associated with this window.
686 int tab_id_;
687
688 // A flag that represents whether or not this tab is active.
689 // This flag is used for preventing us from updating the thumbnail images
690 // when this window is not active.
691 bool tab_active_;
692
693 // An event that represents whether or not we can post a task which updates
694 // the thumbnail image of this window.
695 // We post a task only when this event is signaled.
696 base::WaitableEvent ready_to_update_thumbnail_;
697
698 // The title of this tab.
699 std::wstring title_;
700
701 // The favicon for this tab.
702 SkBitmap favicon_bitmap_;
703 ScopedHICON favicon_;
704
705 // The icon used by the frame window.
706 // This icon is used when this tab doesn't have a favicon.
707 HICON frame_icon_;
708
709 DISALLOW_COPY_AND_ASSIGN(AeroPeekWindow);
710 };
711
712 AeroPeekWindow::AeroPeekWindow(HWND frame_window,
713 AeroPeekWindowDelegate* delegate,
714 int tab_id,
715 bool tab_active,
716 const std::wstring& title,
717 const SkBitmap& favicon_bitmap)
718 : frame_window_(frame_window),
719 delegate_(delegate),
720 tab_id_(tab_id),
721 tab_active_(tab_active),
722 ready_to_update_thumbnail_(false, true),
723 title_(title),
724 favicon_bitmap_(favicon_bitmap),
725 frame_icon_(NULL) {
726 // Set the class styles and window styles for this thumbnail window.
727 // An AeroPeek window should be a tool window. (Otherwise,
728 // Windows doesn't send WM_DWMSENDICONICTHUMBNAIL messages.)
729 set_initial_class_style(0);
730 set_window_style(WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION);
731 set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE);
732 }
733
734 AeroPeekWindow::~AeroPeekWindow() {
735 }
736
737 void AeroPeekWindow::Activate() {
738 tab_active_ = true;
739
740 // Create a place-holder window and add it to the tab list if it has not been
741 // created yet. (This case happens when we re-attached a detached window.)
742 if (!IsWindow(hwnd())) {
743 Update(false);
744 return;
745 }
746
747 // Notify Windows to set the thumbnail focus to this window.
748 ScopedComPtr<ITaskbarList3> taskbar;
749 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
750 CLSCTX_INPROC_SERVER);
751 if (FAILED(result)) {
752 LOG(ERROR) << "failed creating an ITaskbarList3 interface.";
753 return;
754 }
755
756 result = taskbar->HrInit();
757 if (FAILED(result)) {
758 LOG(ERROR) << "failed initializing an ITaskbarList3 interface.";
759 return;
760 }
761
762 result = taskbar->ActivateTab(hwnd());
763 if (FAILED(result)) {
764 LOG(ERROR) << "failed activating a thumbnail window.";
765 return;
766 }
767
768 // Update the thumbnail image to the up-to-date one.
769 UpdateThumbnail();
770 }
771
772 void AeroPeekWindow::Deactivate() {
773 tab_active_ = false;
774 }
775
776 void AeroPeekWindow::Update(bool is_loading) {
777 // Create a place-holder window used by AeroPeek if it has not been created
778 // so Windows can send events used by AeroPeek to this window.
779 // Windows automatically sends a WM_DWMSENDICONICTHUMBNAIL message after this
780 // window is registered to Windows. So, we don't have to invalidate the
781 // thumbnail image of this window now.
782 if (!hwnd()) {
783 gfx::Rect bounds;
784 WindowImpl::Init(NULL, bounds);
785 return;
786 }
787
788 // Invalidate the thumbnail image of this window.
789 // When we invalidate the thumbnail image, we HAVE TO handle a succeeding
790 // WM_DWMSENDICONICTHUMBNAIL message and update the thumbnail image with a
791 // DwmSetIconicThumbnail() call. So, we should not call this function when
792 // we don't have enough information to create a thumbnail.
793 if (tab_active_ || !is_loading)
794 UpdateThumbnail();
795 }
796
797 void AeroPeekWindow::Destroy() {
798 if (!IsWindow(hwnd()))
799 return;
800
801 // Remove this window from the tab list of Windows.
802 ScopedComPtr<ITaskbarList3> taskbar;
803 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
804 CLSCTX_INPROC_SERVER);
805 if (FAILED(result))
806 return;
807
808 result = taskbar->HrInit();
809 if (FAILED(result))
810 return;
811
812 result = taskbar->UnregisterTab(hwnd());
813
814 // Destroy this window.
815 DestroyWindow(hwnd());
816 }
817
818 void AeroPeekWindow::SetTitle(const std::wstring& title) {
819 title_ = title;
820 }
821
822 void AeroPeekWindow::SetFavIcon(const SkBitmap& favicon) {
823 favicon_bitmap_ = favicon;
824 }
825
826 void AeroPeekWindow::UpdateThumbnail() {
827 // We post a task to actually create a new thumbnail. So, this function may
828 // be called while we are creating a thumbnail. To prevent this window from
829 // posting two or more tasks, we don't invalidate the current thumbnail
830 // when this event is not signaled.
831 if (ready_to_update_thumbnail_.IsSignaled())
832 CallDwmInvalidateIconicBitmaps(hwnd());
833 }
834
835 gfx::Rect AeroPeekWindow::GetContentBounds() const {
836 RECT content_rect;
837 GetClientRect(frame_window_, &content_rect);
838
839 gfx::Insets content_insets;
840 delegate_->GetContentInsets(&content_insets);
841
842 gfx::Rect content_bounds(content_rect);
843 content_bounds.Inset(content_insets.left(),
844 content_insets.top(),
845 content_insets.right(),
846 content_insets.bottom());
847 return content_bounds;
848 }
849
850 // message handlers
851
852 void AeroPeekWindow::OnActivate(UINT action,
853 BOOL minimized,
854 HWND window) {
855 // Windows sends a WM_ACTIVATE message not only when a user clicks this
856 // window (i.e. this window gains the thumbnail focus) but also a user clicks
857 // another window (i.e. this window loses the thumbnail focus.)
858 // Return when this window loses the thumbnail focus since we don't have to
859 // do anything for this case.
860 if (action == WA_INACTIVE)
861 return;
862
863 // Ask Chrome to activate the tab associated with this thumbnail window.
864 // Since TabStripModel calls AeroPeekManager::TabSelectedAt() when it
865 // finishes activating the tab. We will move the tab focus of AeroPeek there.
866 if (delegate_)
867 delegate_->ActivateTab(tab_id_);
868 }
869
870 LRESULT AeroPeekWindow::OnCreate(LPCREATESTRUCT create_struct) {
871 // Initialize the window title now since WindowImpl::Init() always calls
872 // CreateWindowEx() with its window name NULL.
873 if (!title_.empty()) {
874 SendMessage(hwnd(), WM_SETTEXT, 0,
875 reinterpret_cast<LPARAM>(title_.c_str()));
876 }
877
878 // Window attributes for DwmSetWindowAttribute().
879 // These enum values are copied from Windows SDK 7 so we can compile this
880 // file with or without it.
881 // TODO(hbono): Bug 16903: to be deleted when we use Windows SDK 7.
882 enum {
883 DWMWA_NCRENDERING_ENABLED = 1,
884 DWMWA_NCRENDERING_POLICY,
885 DWMWA_TRANSITIONS_FORCEDISABLED,
886 DWMWA_ALLOW_NCPAINT,
887 DWMWA_CAPTION_BUTTON_BOUNDS,
888 DWMWA_NONCLIENT_RTL_LAYOUT,
889 DWMWA_FORCE_ICONIC_REPRESENTATION,
890 DWMWA_FLIP3D_POLICY,
891 DWMWA_EXTENDED_FRAME_BOUNDS,
892 DWMWA_HAS_ICONIC_BITMAP,
893 DWMWA_DISALLOW_PEEK,
894 DWMWA_EXCLUDED_FROM_PEEK,
895 DWMWA_LAST
896 };
897
898 // Set DWM attributes to tell Windows that this window can provide the
899 // bitmaps used by AeroPeek.
900 BOOL force_iconic_representation = TRUE;
901 DwmSetWindowAttribute(hwnd(),
902 DWMWA_FORCE_ICONIC_REPRESENTATION,
903 &force_iconic_representation,
904 sizeof(force_iconic_representation));
905
906 BOOL has_iconic_bitmap = TRUE;
907 DwmSetWindowAttribute(hwnd(),
908 DWMWA_HAS_ICONIC_BITMAP,
909 &has_iconic_bitmap,
910 sizeof(has_iconic_bitmap));
911
912 // Post a task that registers this thumbnail window to Windows because it
913 // may take some time. (For example, when we create an ITaskbarList3
914 // interface for the first time, Windows loads DLLs and we need to wait for
915 // some time.)
916 ChromeThread::PostTask(ChromeThread::IO,
917 FROM_HERE,
918 new RegisterThumbnailTask(frame_window_,
919 hwnd(),
920 tab_active_));
921 return 0;
922 }
923
924 void AeroPeekWindow::OnClose() {
925 // Unregister this window from the tab list of Windows and destroy this
926 // window.
927 // The resources attached to this object will be deleted when TabStrip calls
928 // AeroPeekManager::TabClosingAt(). (Please read the comment in TabClosingAt()
929 // for its details.)
930 Destroy();
931
932 // Ask AeroPeekManager to close the tab associated with this thumbnail
933 // window.
934 if (delegate_)
935 delegate_->CloseTab(tab_id_);
936 }
937
938 LRESULT AeroPeekWindow::OnDwmSendIconicThumbnail(UINT message,
939 WPARAM wparam,
940 LPARAM lparam) {
941 // Update the window title to synchronize the title.
942 SendMessage(hwnd(), WM_SETTEXT, 0, reinterpret_cast<LPARAM>(title_.c_str()));
943
944 // Create an I/O task since it takes long time to resize these images and
945 // send them to Windows. This task signals |ready_to_update_thumbnail_| in
946 // its destructor to notify us when this task has been finished. (We create an
947 // I/O task even when the given thumbnail is empty to stop the "loading"
948 // animation.)
949 DCHECK(delegate_);
950
951 SkBitmap thumbnail;
952 delegate_->GetTabThumbnail(tab_id_, &thumbnail);
953
954 gfx::Size aeropeek_size(HIWORD(lparam), LOWORD(lparam));
955 ChromeThread::PostTask(ChromeThread::IO,
956 FROM_HERE,
957 new SendThumbnailTask(hwnd(),
958 GetContentBounds(),
959 aeropeek_size,
960 thumbnail,
961 &ready_to_update_thumbnail_));
962 return 0;
963 }
964
965 LRESULT AeroPeekWindow::OnDwmSendIconicLivePreviewBitmap(UINT message,
966 WPARAM wparam,
967 LPARAM lparam) {
968 // Same as OnDwmSendIconicThumbnail(), we create an I/O task which creates
969 // a preview image used by AeroPeek and send it to Windows. Unlike
970 // OnDwmSendIconicThumbnail(), we don't have to use events for preventing this
971 // window from sending two or more tasks because Windows doesn't send
972 // WM_DWMSENDICONICLIVEPREVIEWBITMAP messages before we send the preview image
973 // to Windows.
974 DCHECK(delegate_);
975
976 SkBitmap preview;
977 delegate_->GetTabPreview(tab_id_, &preview);
978
979 ChromeThread::PostTask(ChromeThread::IO,
980 FROM_HERE,
981 new SendLivePreviewTask(hwnd(),
982 GetContentBounds(),
983 preview));
984 return 0;
985 }
986
987 HICON AeroPeekWindow::OnGetIcon(UINT index) {
988 // Return the application icon if this window doesn't have favicons.
989 // We save this application icon to avoid calling LoadIcon() twice or more.
990 if (favicon_bitmap_.isNull()) {
991 if (!frame_icon_) {
992 frame_icon_ = LoadIcon(GetModuleHandle(chrome::kBrowserResourcesDll),
993 MAKEINTRESOURCE(IDR_MAINFRAME));
994 }
995 return frame_icon_;
996 }
997
998 // Create a Windows icon from SkBitmap and send it to Windows. We set this
999 // icon to the ScopedIcon object to delete it in the destructor.
1000 favicon_.Set(IconUtil::CreateHICONFromSkBitmap(favicon_bitmap_));
1001 return favicon_.Get();
1002 }
1003
1004 AeroPeekManager::AeroPeekManager(HWND application_window)
1005 : application_window_(application_window) {
1006 }
1007
1008 AeroPeekManager::~AeroPeekManager() {
1009 // Delete all AeroPeekWindow objects.
1010 for (std::list<AeroPeekWindow*>::iterator i = tab_list_.begin();
1011 i != tab_list_.end(); ++i) {
1012 AeroPeekWindow* window = *i;
1013 delete window;
1014 }
1015 }
1016
1017 void AeroPeekManager::SetContentInsets(const gfx::Insets& insets) {
1018 content_insets_ = insets;
1019 }
1020
1021 // static
1022 bool AeroPeekManager::Enabled() {
1023 // We enable our custom AeroPeek only when:
1024 // * Chrome is running on Windows 7, and
1025 // * Chrome is not lauched in the application mode.
1026 return win_util::GetWinVersion() >= win_util::WINVERSION_WIN7 &&
1027 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kApp);
1028 }
1029
1030 void AeroPeekManager::DeleteAeroPeekWindow(int tab_id) {
1031 // This function does NOT call AeroPeekWindow::Destroy() before deleting
1032 // the AeroPeekWindow instance.
1033 for (std::list<AeroPeekWindow*>::iterator i = tab_list_.begin();
1034 i != tab_list_.end(); ++i) {
1035 AeroPeekWindow* window = *i;
1036 if (window->tab_id() == tab_id) {
1037 tab_list_.erase(i);
1038 delete window;
1039 return;
1040 }
1041 }
1042 }
1043 AeroPeekWindow* AeroPeekManager::GetAeroPeekWindow(int tab_id) const {
1044 size_t size = tab_list_.size();
1045 for (std::list<AeroPeekWindow*>::const_iterator i = tab_list_.begin();
1046 i != tab_list_.end(); ++i) {
1047 AeroPeekWindow* window = *i;
1048 if (window->tab_id() == tab_id)
1049 return window;
1050 }
1051 return NULL;
1052 }
1053
1054 TabContents* AeroPeekManager::GetTabContents(int tab_id) const {
1055 for (TabContentsIterator iterator; !iterator.done(); ++iterator) {
1056 TabContents* target_contents = *iterator;
1057 if (target_contents->controller().session_id().id() == tab_id)
1058 return target_contents;
1059 }
1060 return NULL;
1061 }
1062
1063 int AeroPeekManager::GetTabID(TabContents* contents) const {
1064 if (!contents)
1065 return -1;
1066 return contents->controller().session_id().id();
1067 }
1068
1069 ///////////////////////////////////////////////////////////////////////////////
1070 // AeroPeekManager, TabStripModelObserver implementation:
1071
1072 void AeroPeekManager::TabInsertedAt(TabContents* contents,
1073 int index,
1074 bool foreground) {
1075 // If there are not any AeroPeekWindow objects associated with the given
1076 // tab, Create a new AeroPeekWindow object and add it to the list.
1077 if (GetAeroPeekWindow(GetTabID(contents)))
1078 return;
1079
1080 AeroPeekWindow* window = new AeroPeekWindow(application_window_,
1081 this,
1082 GetTabID(contents),
1083 foreground,
1084 contents->GetTitle(),
1085 contents->GetFavIcon());
1086 if (!window)
1087 return;
1088
1089 tab_list_.push_back(window);
1090 }
1091
1092 void AeroPeekManager::TabClosingAt(TabContents* contents, int index) {
1093 // Delete the AeroPeekWindow object associated with this tab and all its
1094 // resources. (AeroPeekWindow::Destory() also removes this tab from the tab
1095 // list of Windows.)
1096 AeroPeekWindow* window = GetAeroPeekWindow(GetTabID(contents));
1097 if (!window)
1098 return;
1099
1100 window->Destroy();
1101 DeleteAeroPeekWindow(GetTabID(contents));
1102 }
1103
1104 void AeroPeekManager::TabDetachedAt(TabContents* contents, int index) {
1105 // Same as TabClosingAt(), we remove this tab from the tab list and delete
1106 // its AeroPeekWindow.
1107 // Chrome will call TabInsertedAt() when this tab is inserted to another
1108 // TabStrip. We will re-create an AeroPeekWindow object for this tab and
1109 // re-add it to the tab list there.
1110 TabClosingAt(contents, index);
1111 }
1112
1113 void AeroPeekManager::TabSelectedAt(TabContents* old_contents,
1114 TabContents* new_contents,
1115 int index,
1116 bool user_gesture) {
1117 // Deactivate the old window in the thumbnail list and activate the new one
1118 // to synchronize the thumbnail list with TabStrip.
1119 AeroPeekWindow* old_window = GetAeroPeekWindow(GetTabID(old_contents));
1120 if (old_window)
1121 old_window->Deactivate();
1122
1123 AeroPeekWindow* new_window = GetAeroPeekWindow(GetTabID(new_contents));
1124 if (new_window)
1125 new_window->Activate();
1126 }
1127
1128 void AeroPeekManager::TabMoved(TabContents* contents,
1129 int from_index,
1130 int to_index,
1131 bool pinned_state_changed) {
1132 // TODO(hbono): we need to reorder the thumbnail list of Windows here?
1133 // (Unfortunately, it is not so trivial to reorder the thumbnail list when
1134 // we detach/attach tabs.)
1135 }
1136
1137 void AeroPeekManager::TabChangedAt(TabContents* contents,
1138 int index,
1139 TabChangeType change_type) {
1140 // Retrieve the AeroPeekWindow object associated with this tab, update its
1141 // title, and post a task that update its thumbnail image if necessary.
1142 AeroPeekWindow* window = GetAeroPeekWindow(GetTabID(contents));
1143 if (!window)
1144 return;
1145
1146 // Update the title, the favicon, and the thumbnail used for AeroPeek.
1147 // These function don't actually update the icon and the thumbnail until
1148 // Windows needs them (e.g. when a user hovers a taskbar icon) to avoid
1149 // hurting the rendering performance. (These functions just save the
1150 // information needed for handling update requests from Windows.)
1151 window->SetTitle(contents->GetTitle());
1152 window->SetFavIcon(contents->GetFavIcon());
1153 window->Update(contents->is_loading());
1154 }
1155
1156 ///////////////////////////////////////////////////////////////////////////////
1157 // AeroPeekManager, AeroPeekWindowDelegate implementation:
1158
1159 void AeroPeekManager::ActivateTab(int tab_id) {
1160 // Ask TabStrip to activate this tab.
1161 // We don't have to update thumbnails now since TabStrip will call
1162 // TabSelectedAt() when it actually activates this tab.
1163 TabContents* contents = GetTabContents(tab_id);
1164 if (contents && contents->delegate())
1165 contents->delegate()->ActivateContents(contents);
1166 }
1167
1168 void AeroPeekManager::CloseTab(int tab_id) {
1169 // Ask TabStrip to close this tab.
1170 // TabStrip will call TabClosingAt() when it actually closes this tab. We
1171 // will delete the AeroPeekWindow object attached to this tab there.
1172 TabContents* contents = GetTabContents(tab_id);
1173 if (contents && contents->delegate())
1174 contents->delegate()->CloseContents(contents);
1175 }
1176
1177 void AeroPeekManager::GetContentInsets(gfx::Insets* insets) {
1178 *insets = content_insets_;
1179 }
1180
1181 bool AeroPeekManager::GetTabThumbnail(int tab_id, SkBitmap* thumbnail) {
1182 DCHECK(thumbnail);
1183
1184 // Copy the thumbnail image and the favicon of this tab. We will resize the
1185 // images and send them to Windows.
1186 TabContents* contents = GetTabContents(tab_id);
1187 if (!contents)
1188 return false;
1189
1190 ThumbnailGenerator* generator = g_browser_process->GetThumbnailGenerator();
1191 DCHECK(generator);
1192 *thumbnail = generator->GetThumbnailForRenderer(contents->render_view_host());
1193
1194 return true;
1195 }
1196
1197 bool AeroPeekManager::GetTabPreview(int tab_id, SkBitmap* preview) {
1198 DCHECK(preview);
1199
1200 // Retrieve the BackingStore associated with the given tab and return its
1201 // SkPlatformCanvas.
1202 TabContents* contents = GetTabContents(tab_id);
1203 if (!contents)
1204 return false;
1205
1206 RenderViewHost* render_view_host = contents->render_view_host();
1207 if (!render_view_host)
1208 return false;
1209
1210 BackingStore* backing_store = render_view_host->GetBackingStore(false);
1211 if (!backing_store)
1212 return false;
1213
1214 // Create a copy of this BackingStore image.
1215 // This code is just copied from "thumbnail_generator.cc".
1216 skia::PlatformCanvas canvas;
1217 if (!backing_store->CopyFromBackingStore(gfx::Rect(gfx::Point(0, 0),
1218 backing_store->size()),
1219 &canvas))
1220 return false;
1221
1222 const SkBitmap& bitmap = canvas.getTopPlatformDevice().accessBitmap(false);
1223 bitmap.copyTo(preview, SkBitmap::kARGB_8888_Config);
1224 return true;
1225 }
OLDNEW
« no previous file with comments | « chrome/browser/aeropeek_manager.h ('k') | chrome/browser/views/frame/browser_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698