summaryrefslogtreecommitdiffstats
path: root/cc/test/layer_tree_json_parser.cc
blob: 1514d83487797aa8294f705d97a148fdbf33350a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/test/layer_tree_json_parser.h"

#include "base/test/values_test_util.h"
#include "base/values.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"

namespace cc {

namespace {

scoped_refptr<Layer> ParseTreeFromValue(base::Value* val,
                                        ContentLayerClient* content_client) {
  base::DictionaryValue* dict;
  bool success = true;
  success &= val->GetAsDictionary(&dict);
  std::string layer_type;
  success &= dict->GetString("LayerType", &layer_type);
  base::ListValue* list;
  success &= dict->GetList("Bounds", &list);
  int width, height;
  success &= list->GetInteger(0, &width);
  success &= list->GetInteger(1, &height);
  success &= dict->GetList("Position", &list);
  double position_x, position_y;
  success &= list->GetDouble(0, &position_x);
  success &= list->GetDouble(1, &position_y);

  bool draws_content;
  success &= dict->GetBoolean("DrawsContent", &draws_content);

  scoped_refptr<Layer> new_layer;
  if (layer_type == "SolidColorLayer") {
    new_layer = SolidColorLayer::Create();
  } else if (layer_type == "ContentLayer") {
    new_layer = ContentLayer::Create(content_client);
  } else if (layer_type == "NinePatchLayer") {
    success &= dict->GetList("ImageAperture", &list);
    int aperture_x, aperture_y, aperture_width, aperture_height;
    success &= list->GetInteger(0, &aperture_x);
    success &= list->GetInteger(1, &aperture_y);
    success &= list->GetInteger(2, &aperture_width);
    success &= list->GetInteger(3, &aperture_height);

    base::ListValue* bounds;
    success &= dict->GetList("ImageBounds", &bounds);
    double image_width, image_height;
    success &= bounds->GetDouble(0, &image_width);
    success &= bounds->GetDouble(1, &image_height);

    success &= dict->GetList("Border", &list);
    int border_x, border_y, border_width, border_height;
    success &= list->GetInteger(0, &border_x);
    success &= list->GetInteger(1, &border_y);
    success &= list->GetInteger(2, &border_width);
    success &= list->GetInteger(3, &border_height);

    bool fill_center;
    success &= dict->GetBoolean("FillCenter", &fill_center);

    scoped_refptr<NinePatchLayer> nine_patch_layer = NinePatchLayer::Create();

    SkBitmap bitmap;
    bitmap.allocN32Pixels(image_width, image_height);
    bitmap.setImmutable();
    nine_patch_layer->SetBitmap(bitmap);
    nine_patch_layer->SetAperture(
        gfx::Rect(aperture_x, aperture_y, aperture_width, aperture_height));
    nine_patch_layer->SetBorder(
        gfx::Rect(border_x, border_y, border_width, border_height));
    nine_patch_layer->SetFillCenter(fill_center);

    new_layer = nine_patch_layer;
  } else if (layer_type == "TextureLayer") {
    new_layer = TextureLayer::CreateForMailbox(NULL);
  } else if (layer_type == "PictureLayer") {
    new_layer = PictureLayer::Create(content_client);
  } else {  // Type "Layer" or "unknown"
    new_layer = Layer::Create();
  }
  new_layer->SetPosition(gfx::PointF(position_x, position_y));
  new_layer->SetBounds(gfx::Size(width, height));
  new_layer->SetIsDrawable(draws_content);

  double opacity;
  if (dict->GetDouble("Opacity", &opacity))
    new_layer->SetOpacity(opacity);

  bool contents_opaque;
  if (dict->GetBoolean("ContentsOpaque", &contents_opaque))
    new_layer->SetContentsOpaque(contents_opaque);

  bool scrollable;
  // TODO(wjmaclean) At some time in the future we may wish to test that a
  // reconstructed layer tree contains the correct linkage for the scroll
  // clip layer. This is complicated by the fact that the json output doesn't
  // (currently) re-construct the tree with the same layer IDs as the original.
  // But, since a clip layer is always an ancestor of the scrollable layer, we
  // can just count the number of upwards hops to the clip layer and write that
  // into the json file (with 0 hops implying no clip layer, i.e. not
  // scrollable). Reconstructing the tree can then be accomplished by passing
  // the parent pointer to this function and traversing the same number of
  // ancestors to determine the pointer to the clip layer. The LayerTreesMatch()
  // function should then check that both original and reconstructed layers
  // have the same positioning with respect to their clip layers.
  //
  // For now, we can safely indicate a layer is scrollable by giving it a
  // pointer to itself, something not normally allowed in a working tree.
  //
  // https://code.google.com/p/chromium/issues/detail?id=330622
  //
  if (dict->GetBoolean("Scrollable", &scrollable))
    new_layer->SetScrollClipLayerId(scrollable ? new_layer->id()
                                               : Layer::INVALID_ID);

  bool wheel_handler;
  if (dict->GetBoolean("WheelHandler", &wheel_handler))
    new_layer->SetHaveWheelEventHandlers(wheel_handler);

  bool scroll_handler;
  if (dict->GetBoolean("ScrollHandler", &scroll_handler))
    new_layer->SetHaveScrollEventHandlers(scroll_handler);

  bool is_3d_sorted;
  if (dict->GetBoolean("Is3DSorted", &is_3d_sorted)) {
    // A non-zero context ID will put the layer into a 3D sorting context
    new_layer->Set3dSortingContextId(is_3d_sorted ? 1 : 0);
  }

  if (dict->HasKey("TouchRegion")) {
    success &= dict->GetList("TouchRegion", &list);
    Region touch_region;
    for (size_t i = 0; i < list->GetSize(); ) {
      int rect_x, rect_y, rect_width, rect_height;
      success &= list->GetInteger(i++, &rect_x);
      success &= list->GetInteger(i++, &rect_y);
      success &= list->GetInteger(i++, &rect_width);
      success &= list->GetInteger(i++, &rect_height);
      touch_region.Union(gfx::Rect(rect_x, rect_y, rect_width, rect_height));
    }
    new_layer->SetTouchEventHandlerRegion(touch_region);
  }

  success &= dict->GetList("DrawTransform", &list);
  double transform[16];
  for (int i = 0; i < 16; ++i)
    success &= list->GetDouble(i, &transform[i]);

  gfx::Transform layer_transform;
  layer_transform.matrix().setColMajord(transform);
  new_layer->SetTransform(layer_transform);

  success &= dict->GetList("Children", &list);
  for (base::ListValue::const_iterator it = list->begin();
       it != list->end(); ++it) {
    new_layer->AddChild(ParseTreeFromValue(*it, content_client));
  }

  if (!success)
    return NULL;

  return new_layer;
}

}  // namespace

scoped_refptr<Layer> ParseTreeFromJson(std::string json,
                                       ContentLayerClient* content_client) {
  scoped_ptr<base::Value> val = base::test::ParseJson(json);
  return ParseTreeFromValue(val.get(), content_client);
}

}  // namespace cc