blob: 06b35527464dd252a914c7d7066289ee8a69adbe [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/debug/dom_component.h"
#include <string>
#include "base/bind.h"
#include "cobalt/math/matrix3_f.h"
#include "cobalt/math/transform_2d.h"
#include "cobalt/render_tree/brush.h"
#include "cobalt/render_tree/color_rgba.h"
#include "cobalt/render_tree/rect_node.h"
namespace cobalt {
namespace debug {
namespace {
// File to load JavaScript DOM debugging domain implementation from.
const char kScriptFile[] = "dom.js";
// Command "methods" (names) from the set specified here:
// https://developer.chrome.com/devtools/docs/protocol/1.1/dom
const char kDisable[] = "DOM.disable";
const char kEnable[] = "DOM.enable";
const char kGetDocument[] = "DOM.getDocument";
const char kRequestChildNodes[] = "DOM.requestChildNodes";
const char kRequestNode[] = "DOM.requestNode";
const char kResolveNode[] = "DOM.resolveNode";
const char kHideHighlight[] = "DOM.hideHighlight";
const char kHighlightNode[] = "DOM.highlightNode";
// Parameter names:
const char kA[] = "a";
const char kB[] = "b";
const char kContentColor[] = "contentColor";
const char kG[] = "g";
const char kHighlightConfig[] = "highlightConfig";
const char kR[] = "r";
} // namespace
DOMComponent::DOMComponent(ComponentConnector* connector,
scoped_ptr<RenderLayer> render_layer)
: connector_(connector), render_layer_(render_layer.Pass()) {
DCHECK(connector_);
connector_->AddCommand(
kDisable, base::Bind(&DOMComponent::Disable, base::Unretained(this)));
connector_->AddCommand(
kEnable, base::Bind(&DOMComponent::Enable, base::Unretained(this)));
connector_->AddCommand(kGetDocument, base::Bind(&DOMComponent::GetDocument,
base::Unretained(this)));
connector_->AddCommand(
kRequestChildNodes,
base::Bind(&DOMComponent::RequestChildNodes, base::Unretained(this)));
connector_->AddCommand(kRequestNode, base::Bind(&DOMComponent::RequestNode,
base::Unretained(this)));
connector_->AddCommand(kResolveNode, base::Bind(&DOMComponent::ResolveNode,
base::Unretained(this)));
connector_->AddCommand(
kHighlightNode,
base::Bind(&DOMComponent::HighlightNode, base::Unretained(this)));
connector_->AddCommand(
kHideHighlight,
base::Bind(&DOMComponent::HideHighlight, base::Unretained(this)));
}
JSONObject DOMComponent::Enable(const JSONObject& params) {
UNREFERENCED_PARAMETER(params);
bool initialized = connector_->RunScriptFile(kScriptFile);
if (initialized) {
return JSONObject(new base::DictionaryValue());
} else {
return connector_->ErrorResponse("Cannot create DOM inspector.");
}
}
JSONObject DOMComponent::Disable(const JSONObject& params) {
UNREFERENCED_PARAMETER(params);
return JSONObject(new base::DictionaryValue());
}
JSONObject DOMComponent::GetDocument(const JSONObject& params) {
return connector_->RunScriptCommand("dom.getDocument", params);
}
JSONObject DOMComponent::RequestChildNodes(const JSONObject& params) {
return connector_->RunScriptCommand("dom.requestChildNodes", params);
}
JSONObject DOMComponent::RequestNode(const JSONObject& params) {
return connector_->RunScriptCommand("dom.requestNode", params);
}
JSONObject DOMComponent::ResolveNode(const JSONObject& params) {
return connector_->RunScriptCommand("dom.resolveNode", params);
}
// Unlike most other DOM command handlers, this one is not fully implemented
// in JavaScript. Instead, the JS object is used to look up the node from the
// parameters and return its bounding client rect, then the highlight itself
// is rendered by calling the C++ function |RenderHighlight| to set the render
// overlay.
JSONObject DOMComponent::HighlightNode(const JSONObject& params) {
// Get the bounding rectangle of the specified node.
JSONObject json_dom_rect =
connector_->RunScriptCommand("dom.getBoundingClientRect", params);
double x = 0.0;
double y = 0.0;
double width = 0.0;
double height = 0.0;
json_dom_rect->GetDouble("result.x", &x);
json_dom_rect->GetDouble("result.y", &y);
json_dom_rect->GetDouble("result.width", &width);
json_dom_rect->GetDouble("result.height", &height);
scoped_refptr<dom::DOMRect> dom_rect(
new dom::DOMRect(static_cast<float>(x), static_cast<float>(y),
static_cast<float>(width), static_cast<float>(height)));
// |highlight_config_value| still owned by |params|.
base::DictionaryValue* highlight_config_value = NULL;
bool got_highlight_config =
params->GetDictionary(kHighlightConfig, &highlight_config_value);
DCHECK(got_highlight_config);
DCHECK(highlight_config_value);
RenderHighlight(dom_rect, highlight_config_value);
// Empty response.
return JSONObject(new base::DictionaryValue());
}
JSONObject DOMComponent::HideHighlight(const JSONObject& params) {
UNREFERENCED_PARAMETER(params);
render_layer_->SetFrontLayer(scoped_refptr<render_tree::Node>());
// Empty response.
return JSONObject(new base::DictionaryValue());
}
void DOMComponent::RenderHighlight(
const scoped_refptr<dom::DOMRect>& bounding_rect,
const base::DictionaryValue* highlight_config_value) {
// TODO: Should also render borders, etc.
// Content color is optional in the parameters, so use a fallback.
int r = 112;
int g = 168;
int b = 219;
double a = 0.66;
const base::DictionaryValue* content_color = NULL;
bool got_content_color =
highlight_config_value->GetDictionary(kContentColor, &content_color);
if (got_content_color && content_color) {
content_color->GetInteger(kR, &r);
content_color->GetInteger(kG, &g);
content_color->GetInteger(kB, &b);
content_color->GetDouble(kA, &a);
}
render_tree::ColorRGBA color(r / 255.0f, g / 255.0f, b / 255.0f,
static_cast<float>(a));
scoped_ptr<render_tree::Brush> background_brush(
new render_tree::SolidColorBrush(color));
scoped_refptr<render_tree::Node> rect = new render_tree::RectNode(
math::RectF(bounding_rect->x(), bounding_rect->y(),
bounding_rect->width(), bounding_rect->height()),
background_brush.Pass());
render_layer_->SetFrontLayer(rect);
}
} // namespace debug
} // namespace cobalt