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 "ui/surface/transport_dib.h"
6
7#include <windows.h>
8
9#include <limits>
10
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/sys_info.h"
14#include "skia/ext/platform_canvas.h"
15
16TransportDIB::TransportDIB()
17    : size_(0) {
18}
19
20TransportDIB::~TransportDIB() {
21}
22
23TransportDIB::TransportDIB(HANDLE handle)
24    : shared_memory_(handle, false /* read write */),
25      size_(0) {
26}
27
28// static
29TransportDIB* TransportDIB::Create(size_t size, uint32 sequence_num) {
30  TransportDIB* dib = new TransportDIB;
31
32  if (!dib->shared_memory_.CreateAnonymous(size)) {
33    delete dib;
34    return NULL;
35  }
36
37  dib->size_ = size;
38  dib->sequence_num_ = sequence_num;
39
40  return dib;
41}
42
43// static
44TransportDIB* TransportDIB::Map(Handle handle) {
45  scoped_ptr<TransportDIB> dib(CreateWithHandle(handle));
46  if (!dib->Map())
47    return NULL;
48  return dib.release();
49}
50
51// static
52TransportDIB* TransportDIB::CreateWithHandle(Handle handle) {
53  return new TransportDIB(handle);
54}
55
56// static
57bool TransportDIB::is_valid_handle(Handle dib) {
58  return dib != NULL;
59}
60
61// static
62bool TransportDIB::is_valid_id(TransportDIB::Id id) {
63  return is_valid_handle(id.handle);
64}
65
66skia::PlatformCanvas* TransportDIB::GetPlatformCanvas(int w, int h) {
67  // This DIB already mapped the file into this process, but PlatformCanvas
68  // will map it again.
69  DCHECK(!memory()) << "Mapped file twice in the same process.";
70
71  // We can't check the canvas size before mapping, but it's safe because
72  // Windows will fail to map the section if the dimensions of the canvas
73  // are too large.
74  skia::PlatformCanvas* canvas =
75      skia::CreatePlatformCanvas(w, h, true, handle(),
76                                 skia::RETURN_NULL_ON_FAILURE);
77
78  // Calculate the size for the memory region backing the canvas.
79  if (canvas)
80    size_ = skia::PlatformCanvasStrideForWidth(w) * h;
81
82  return canvas;
83}
84
85bool TransportDIB::Map() {
86  if (!is_valid_handle(handle()))
87    return false;
88  if (memory())
89    return true;
90
91  if (!shared_memory_.Map(0 /* map whole shared memory segment */)) {
92    LOG(ERROR) << "Failed to map transport DIB"
93               << " handle:" << shared_memory_.handle()
94               << " error:" << ::GetLastError();
95    return false;
96  }
97
98  size_ = shared_memory_.mapped_size();
99  return true;
100}
101
102void* TransportDIB::memory() const {
103  return shared_memory_.memory();
104}
105
106TransportDIB::Handle TransportDIB::handle() const {
107  return shared_memory_.handle();
108}
109
110TransportDIB::Id TransportDIB::id() const {
111  return Id(handle(), sequence_num_);
112}
113