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 "chrome/browser/ui/cocoa/table_row_nsimage_cache.h"
6
7#include "base/logging.h"
8#include "ui/gfx/image/image_skia.h"
9#include "ui/gfx/image/image_skia_util_mac.h"
10
11TableRowNSImageCache::TableRowNSImageCache(Table* model)
12    : model_(model),
13      icon_images_([[NSPointerArray alloc] initWithOptions:
14          NSPointerFunctionsStrongMemory |
15          NSPointerFunctionsObjectPersonality]) {
16  int count = model_->RowCount();
17  [icon_images_ setCount:count];
18}
19
20TableRowNSImageCache::~TableRowNSImageCache() {}
21
22void TableRowNSImageCache::OnModelChanged() {
23  int count = model_->RowCount();
24  [icon_images_ setCount:0];
25  [icon_images_ setCount:count];
26}
27
28void TableRowNSImageCache::OnItemsChanged(int start, int length) {
29  DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
30  for (int i = start; i < (start + length); ++i) {
31    [icon_images_ replacePointerAtIndex:i withPointer:NULL];
32  }
33  DCHECK_EQ(model_->RowCount(),
34            static_cast<int>([icon_images_ count]));
35}
36
37void TableRowNSImageCache::OnItemsAdded(int start, int length) {
38  DCHECK_LE(start, static_cast<int>([icon_images_ count]));
39
40  // -[NSPointerArray insertPointer:atIndex:] throws if index == count.
41  // Instead expand the array with NULLs.
42  if (start == static_cast<int>([icon_images_ count])) {
43    [icon_images_ setCount:start + length];
44  } else {
45    for (int i = 0; i < length; ++i) {
46      [icon_images_ insertPointer:NULL atIndex:start];  // Values slide up.
47    }
48  }
49  DCHECK_EQ(model_->RowCount(),
50            static_cast<int>([icon_images_ count]));
51}
52
53void TableRowNSImageCache::OnItemsRemoved(int start, int length) {
54  DCHECK_LE(start + length, static_cast<int>([icon_images_ count]));
55  for (int i = 0; i < length; ++i) {
56    [icon_images_ removePointerAtIndex:start];  // Values slide down.
57  }
58  DCHECK_EQ(model_->RowCount(),
59            static_cast<int>([icon_images_ count]));
60}
61
62NSImage* TableRowNSImageCache::GetImageForRow(int row) {
63  DCHECK_EQ(model_->RowCount(),
64            static_cast<int>([icon_images_ count]));
65  DCHECK_GE(row, 0);
66  DCHECK_LT(row, static_cast<int>([icon_images_ count]));
67  NSImage* image = static_cast<NSImage*>([icon_images_ pointerAtIndex:row]);
68  if (!image) {
69    const gfx::ImageSkia image_skia_icon =
70        model_->GetIcon(row);
71    // This means GetIcon() will get called until it returns a non-empty image.
72    // Empty images are intentionally not cached.
73    if (!image_skia_icon.isNull()) {
74      image = gfx::NSImageFromImageSkia(image_skia_icon);
75      DCHECK(image);
76      [icon_images_ replacePointerAtIndex:row withPointer:image];
77    }
78  }
79  return image;
80}
81
82