blob: d517a4f1da47e8b41cd0e5e895202ffa8f2b5dfc [file] [log] [blame]
/*
* Copyright 2014 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/layout/layout.h"
#include "base/debug/trace_event.h"
#include "cobalt/base/stop_watch.h"
#include "cobalt/cssom/computed_style.h"
#include "cobalt/cssom/css_style_declaration.h"
#include "cobalt/dom/document.h"
#include "cobalt/dom/html_body_element.h"
#include "cobalt/dom/html_element_context.h"
#include "cobalt/dom/html_html_element.h"
#include "cobalt/layout/benchmark_stat_names.h"
#include "cobalt/layout/box_generator.h"
#include "cobalt/layout/initial_containing_block.h"
#include "cobalt/layout/used_style.h"
#include "cobalt/render_tree/animations/animate_node.h"
namespace cobalt {
namespace layout {
namespace {
class ScopedParagraph {
public:
explicit ScopedParagraph(const scoped_refptr<Paragraph>& paragraph)
: paragraph_(paragraph) {}
~ScopedParagraph() { paragraph_->Close(); }
scoped_refptr<Paragraph>& get() { return paragraph_; }
private:
scoped_refptr<Paragraph> paragraph_;
};
} // namespace
void UpdateComputedStylesAndLayoutBoxTree(
const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
UsedStyleProvider* used_style_provider,
LayoutStatTracker* layout_stat_tracker,
icu::BreakIterator* line_break_iterator,
icu::BreakIterator* character_break_iterator,
scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block) {
TRACE_EVENT0("cobalt::layout", "UpdateComputedStylesAndLayoutBoxTree()");
// Layout-related cleanup is performed on the UsedStyleProvider in this
// object's destructor.
UsedStyleProviderLayoutScope used_style_provider_layout_scope(
used_style_provider);
// Update the computed style of all elements in the DOM, if necessary.
document->UpdateComputedStyles();
base::StopWatch stop_watch_layout_box_tree(
LayoutStatTracker::kStopWatchTypeLayoutBoxTree,
base::StopWatch::kAutoStartOn, layout_stat_tracker);
// Create initial containing block.
InitialContainingBlockCreationResults
initial_containing_block_creation_results = CreateInitialContainingBlock(
document->initial_computed_style_data(), document,
used_style_provider, layout_stat_tracker);
*initial_containing_block = initial_containing_block_creation_results.box;
// Generate boxes.
{
TRACE_EVENT0("cobalt::layout", kBenchmarkStatBoxGeneration);
base::StopWatch stop_watch_box_generation(
LayoutStatTracker::kStopWatchTypeBoxGeneration,
base::StopWatch::kAutoStartOn, layout_stat_tracker);
ScopedParagraph scoped_paragraph(
new Paragraph(locale, (*initial_containing_block)->GetBaseDirection(),
Paragraph::DirectionalEmbeddingStack(),
line_break_iterator, character_break_iterator));
BoxGenerator::Context context(
used_style_provider, layout_stat_tracker, line_break_iterator,
character_break_iterator,
initial_containing_block_creation_results.background_style_source);
BoxGenerator root_box_generator(
(*initial_containing_block)->css_computed_style_declaration(),
(*initial_containing_block)
->css_computed_style_declaration()
->animations(),
&(scoped_paragraph.get()), &context);
document->html()->Accept(&root_box_generator);
const Boxes& root_boxes = root_box_generator.boxes();
for (Boxes::const_iterator root_box_iterator = root_boxes.begin();
root_box_iterator != root_boxes.end(); ++root_box_iterator) {
(*initial_containing_block)->AddChild(*root_box_iterator);
}
}
// Split bidi level runs.
// The bidi levels were calculated for the paragraphs during box generation.
// Now the text boxes are split between level runs, so that they will be
// reversible during layout without requiring additional run-induced splits.
{
TRACE_EVENT0("cobalt::layout", "SplitBidiLevelRuns");
(*initial_containing_block)->SplitBidiLevelRuns();
}
// Layout.
{
TRACE_EVENT0("cobalt::layout", kBenchmarkStatUpdateUsedSizes);
base::StopWatch stop_watch_update_used_sizes(
LayoutStatTracker::kStopWatchTypeUpdateUsedSizes,
base::StopWatch::kAutoStartOn, layout_stat_tracker);
(*initial_containing_block)->set_left(LayoutUnit());
(*initial_containing_block)->set_top(LayoutUnit());
(*initial_containing_block)->UpdateSize(LayoutParams());
}
}
scoped_refptr<render_tree::Node> Layout(
const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
UsedStyleProvider* used_style_provider,
LayoutStatTracker* layout_stat_tracker,
icu::BreakIterator* line_break_iterator,
icu::BreakIterator* character_break_iterator,
scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block) {
TRACE_EVENT0("cobalt::layout", "Layout()");
UpdateComputedStylesAndLayoutBoxTree(
locale, document, used_style_provider, layout_stat_tracker,
line_break_iterator, character_break_iterator, initial_containing_block);
// Add to render tree.
render_tree::CompositionNode::Builder render_tree_root_builder;
{
TRACE_EVENT0("cobalt::layout", kBenchmarkStatRenderAndAnimate);
base::StopWatch stop_watch_render_and_animate(
LayoutStatTracker::kStopWatchTypeRenderAndAnimate,
base::StopWatch::kAutoStartOn, layout_stat_tracker);
(*initial_containing_block)
->RenderAndAnimate(&render_tree_root_builder, math::Vector2dF(0, 0));
}
render_tree::CompositionNode* static_root_node =
new render_tree::CompositionNode(render_tree_root_builder.Pass());
// Make it easy to animate the entire tree by placing an AnimateNode at the
// root to merge any sub-AnimateNodes.
render_tree::animations::AnimateNode* animate_node =
new render_tree::animations::AnimateNode(static_root_node);
return animate_node;
}
} // namespace layout
} // namespace cobalt