diff --git a/DEPS b/DEPS index 335af88e..d001dae 100644 --- a/DEPS +++ b/DEPS
@@ -36,7 +36,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '0e72e9ee3b0201f05e5d74917b17c8a427b14d9f', + 'skia_revision': '057ae8a15ddd2af639a829d63aca29cbc6b1bb57', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other.
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h index b2b98b4..53a72924 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -16,7 +16,6 @@ #include "third_party/skia/include/core/SkColor.h" namespace gfx { -class FontList; class Point; class Rect; } @@ -56,13 +55,6 @@ // Removes the suggestion at the given index. virtual bool RemoveSuggestion(int index) = 0; -#if !defined(OS_ANDROID) - // The same font can vary based on the type of data it is showing, - // so we need to know the row. - virtual const gfx::FontList& GetValueFontListForRow(size_t index) const = 0; - virtual const gfx::FontList& GetLabelFontList() const = 0; -#endif - // Returns the background color of the row item according to its |index|, or // transparent if the default popup background should be used. virtual SkColor GetBackgroundColorForRow(int index) const = 0;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index e1bbe01..2e21fe04 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -19,6 +19,7 @@ #include "components/autofill/core/browser/suggestion.h" #include "content/public/browser/native_web_keyboard_event.h" #include "ui/events/event.h" +#include "ui/gfx/canvas.h" #include "ui/gfx/text_elider.h" #include "ui/gfx/text_utils.h" @@ -30,11 +31,6 @@ // Used to indicate that no line is currently selected by the user. const int kNoSelection = -1; -#if !defined(OS_ANDROID) -// Size difference between the normal font and the smaller font, in pixels. -const int kSmallerFontSizeDelta = -1; -#endif - } // namespace // static @@ -81,17 +77,6 @@ controller_common_->SetKeyPressCallback( base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, base::Unretained(this))); -#if !defined(OS_ANDROID) - smaller_font_list_ = - normal_font_list_.DeriveWithSizeDelta(kSmallerFontSizeDelta); - bold_font_list_ = normal_font_list_.DeriveWithWeight(gfx::Font::Weight::BOLD); -#if defined(OS_MACOSX) - // There is no italic version of the system font. - warning_font_list_ = normal_font_list_; -#else - warning_font_list_ = normal_font_list_.DeriveWithStyle(gfx::Font::ITALIC); -#endif -#endif } AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} @@ -334,11 +319,12 @@ #if !defined(OS_ANDROID) int AutofillPopupControllerImpl::GetElidedValueWidthForRow(size_t row) { return gfx::GetStringWidth(GetElidedValueAt(row), - GetValueFontListForRow(row)); + layout_model_.GetValueFontListForRow(row)); } int AutofillPopupControllerImpl::GetElidedLabelWidthForRow(size_t row) { - return gfx::GetStringWidth(GetElidedLabelAt(row), GetLabelFontList()); + return gfx::GetStringWidth(GetElidedLabelAt(row), + layout_model_.GetLabelFontList()); } #endif @@ -393,40 +379,6 @@ return true; } -#if !defined(OS_ANDROID) -const gfx::FontList& AutofillPopupControllerImpl::GetValueFontListForRow( - size_t index) const { - // Autofill values have positive |frontend_id|. - if (suggestions_[index].frontend_id > 0) - return bold_font_list_; - - // All other message types are defined here. - PopupItemId id = static_cast<PopupItemId>(suggestions_[index].frontend_id); - switch (id) { - case POPUP_ITEM_ID_WARNING_MESSAGE: - return warning_font_list_; - case POPUP_ITEM_ID_CLEAR_FORM: - case POPUP_ITEM_ID_AUTOFILL_OPTIONS: - case POPUP_ITEM_ID_SCAN_CREDIT_CARD: - case POPUP_ITEM_ID_SEPARATOR: - return normal_font_list_; - case POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO: - return smaller_font_list_; - case POPUP_ITEM_ID_TITLE: - case POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY: - case POPUP_ITEM_ID_DATALIST_ENTRY: - case POPUP_ITEM_ID_PASSWORD_ENTRY: - return bold_font_list_; - } - NOTREACHED(); - return normal_font_list_; -} - -const gfx::FontList& AutofillPopupControllerImpl::GetLabelFontList() const { - return smaller_font_list_; -} -#endif - SkColor AutofillPopupControllerImpl::GetBackgroundColorForRow(int index) const { if (index == selected_line_) return kHoveredBackgroundColor; @@ -556,10 +508,10 @@ void AutofillPopupControllerImpl::ElideValueAndLabelForRow( size_t row, int available_width) { - int value_width = - gfx::GetStringWidth(suggestions_[row].value, GetValueFontListForRow(row)); - int label_width = - gfx::GetStringWidth(suggestions_[row].label, GetLabelFontList()); + int value_width = gfx::GetStringWidth( + suggestions_[row].value, layout_model_.GetValueFontListForRow(row)); + int label_width = gfx::GetStringWidth(suggestions_[row].label, + layout_model_.GetLabelFontList()); int total_text_length = value_width + label_width; // The line can have no strings if it represents a UI element, such as @@ -569,13 +521,14 @@ // Each field receives space in proportion to its length. int value_size = available_width * value_width / total_text_length; - elided_values_[row] = - gfx::ElideText(suggestions_[row].value, GetValueFontListForRow(row), - value_size, gfx::ELIDE_TAIL); + elided_values_[row] = gfx::ElideText( + suggestions_[row].value, layout_model_.GetValueFontListForRow(row), + value_size, gfx::ELIDE_TAIL); int label_size = available_width * label_width / total_text_length; - elided_labels_[row] = gfx::ElideText( - suggestions_[row].label, GetLabelFontList(), label_size, gfx::ELIDE_TAIL); + elided_labels_[row] = + gfx::ElideText(suggestions_[row].label, layout_model_.GetLabelFontList(), + label_size, gfx::ELIDE_TAIL); } #endif
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h index 4dc894b8..c39dc6d6 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -15,7 +15,6 @@ #include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "chrome/browser/ui/autofill/autofill_popup_layout_model.h" #include "chrome/browser/ui/autofill/popup_controller_common.h" -#include "ui/gfx/font_list.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect_f.h" @@ -97,10 +96,6 @@ base::string16* title, base::string16* body) override; bool RemoveSuggestion(int list_index) override; -#if !defined(OS_ANDROID) - const gfx::FontList& GetValueFontListForRow(size_t index) const override; - const gfx::FontList& GetLabelFontList() const override; -#endif SkColor GetBackgroundColorForRow(int index) const override; int selected_line() const override; const AutofillPopupLayoutModel& layout_model() const override; @@ -170,19 +165,6 @@ std::vector<base::string16> elided_values_; std::vector<base::string16> elided_labels_; -#if !defined(OS_ANDROID) - // The fonts for the popup text. - // Normal font (readable size, non bold). - gfx::FontList normal_font_list_; - // Slightly smaller than the normal font. - gfx::FontList smaller_font_list_; - // Bold version of the normal font. - gfx::FontList bold_font_list_; - // Font used for the warning dialog, which may be italic or not depending on - // the platform. - gfx::FontList warning_font_list_; -#endif - // The line that is currently selected by the user. // |kNoSelection| indicates that no line is currently selected. int selected_line_;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index f606678..ce2f055 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -93,10 +93,6 @@ using AutofillPopupControllerImpl::RemoveSelectedLine; using AutofillPopupControllerImpl::popup_bounds; using AutofillPopupControllerImpl::element_bounds; -#if !defined(OS_ANDROID) - using AutofillPopupControllerImpl::GetValueFontListForRow; - using AutofillPopupControllerImpl::GetLabelFontList; -#endif using AutofillPopupControllerImpl::SetValues; using AutofillPopupControllerImpl::GetWeakPtr; MOCK_METHOD1(InvalidateRow, void(size_t)); @@ -445,10 +441,12 @@ int popup_max_width = gfx::GetStringWidth( suggestions[0].value, - autofill_popup_controller_->GetValueFontListForRow(0)) + + autofill_popup_controller_->layout_model().GetValueFontListForRow( + 0)) + gfx::GetStringWidth( suggestions[0].label, - autofill_popup_controller_->GetLabelFontList()) - 25; + autofill_popup_controller_->layout_model().GetLabelFontList()) - + 25; autofill_popup_controller_->ElideValueAndLabelForRow(0, popup_max_width);
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc index 986a516..5f592fd 100644 --- a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc +++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
@@ -15,6 +15,7 @@ #include "components/autofill/core/common/autofill_util.h" #include "grit/components_scaled_resources.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font_list.h" #include "ui/gfx/geometry/rect_conversions.h" namespace autofill { @@ -27,6 +28,11 @@ // The vertical height of a separator in pixels. const size_t kSeparatorHeight = 1; +#if !defined(OS_ANDROID) +// Size difference between the normal font and the smaller font, in pixels. +const int kSmallerFontSizeDelta = -1; +#endif + const struct { const char* name; int id; @@ -55,7 +61,21 @@ AutofillPopupLayoutModel::AutofillPopupLayoutModel( AutofillPopupViewDelegate* delegate) - : delegate_(delegate) {} + : delegate_(delegate) { +#if !defined(OS_ANDROID) + smaller_font_list_ = + normal_font_list_.DeriveWithSizeDelta(kSmallerFontSizeDelta); + bold_font_list_ = normal_font_list_.DeriveWithWeight(gfx::Font::Weight::BOLD); +#if defined(OS_MACOSX) + // There is no italic version of the system font. + warning_font_list_ = normal_font_list_; +#else + warning_font_list_ = normal_font_list_.DeriveWithStyle(gfx::Font::ITALIC); +#endif +#endif +} + +AutofillPopupLayoutModel::~AutofillPopupLayoutModel() {} #if !defined(OS_ANDROID) int AutofillPopupLayoutModel::GetDesiredPopupHeight() const { @@ -125,6 +145,40 @@ popup_width, popup_height, RoundedElementBounds(), delegate_->container_view(), delegate_->IsRTL()); } + +const gfx::FontList& AutofillPopupLayoutModel::GetValueFontListForRow( + size_t index) const { + std::vector<autofill::Suggestion> suggestions = delegate_->GetSuggestions(); + + // Autofill values have positive |frontend_id|. + if (suggestions[index].frontend_id > 0) + return bold_font_list_; + + // All other message types are defined here. + PopupItemId id = static_cast<PopupItemId>(suggestions[index].frontend_id); + switch (id) { + case POPUP_ITEM_ID_WARNING_MESSAGE: + return warning_font_list_; + case POPUP_ITEM_ID_CLEAR_FORM: + case POPUP_ITEM_ID_AUTOFILL_OPTIONS: + case POPUP_ITEM_ID_SCAN_CREDIT_CARD: + case POPUP_ITEM_ID_SEPARATOR: + return normal_font_list_; + case POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO: + return smaller_font_list_; + case POPUP_ITEM_ID_TITLE: + case POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY: + case POPUP_ITEM_ID_DATALIST_ENTRY: + case POPUP_ITEM_ID_PASSWORD_ENTRY: + return bold_font_list_; + } + NOTREACHED(); + return normal_font_list_; +} + +const gfx::FontList& AutofillPopupLayoutModel::GetLabelFontList() const { + return smaller_font_list_; +} #endif int AutofillPopupLayoutModel::LineFromY(int y) const {
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.h b/chrome/browser/ui/autofill/autofill_popup_layout_model.h index aad29d1..0e90842 100644 --- a/chrome/browser/ui/autofill/autofill_popup_layout_model.h +++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.h
@@ -10,6 +10,7 @@ #include "base/strings/string16.h" #include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h" #include "chrome/browser/ui/autofill/popup_view_common.h" +#include "ui/gfx/font_list.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/native_widget_types.h" @@ -29,6 +30,7 @@ class AutofillPopupLayoutModel { public: explicit AutofillPopupLayoutModel(AutofillPopupViewDelegate* delegate); + ~AutofillPopupLayoutModel(); // The minimum amount of padding between the Autofill name and subtext, // in pixels. @@ -60,6 +62,11 @@ // Calculates and sets the bounds of the popup, including placing it properly // to prevent it from going off the screen. void UpdatePopupBounds(); + + // The same font can vary based on the type of data it is showing at the row + // |index|. + const gfx::FontList& GetValueFontListForRow(size_t index) const; + const gfx::FontList& GetLabelFontList() const; #endif // Convert a y-coordinate to the closest line. @@ -79,6 +86,19 @@ // Returns the enclosing rectangle for the element_bounds. const gfx::Rect RoundedElementBounds() const; +#if !defined(OS_ANDROID) + // The fonts for the popup text. + // Normal font (readable size, non bold). + gfx::FontList normal_font_list_; + // Slightly smaller than the normal font. + gfx::FontList smaller_font_list_; + // Bold version of the normal font. + gfx::FontList bold_font_list_; + // Font used for the warning dialog, which may be italic or not depending on + // the platform. + gfx::FontList warning_font_list_; +#endif + // The bounds of the Autofill popup. gfx::Rect popup_bounds_;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm index c368b4c..35856a79 100644 --- a/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm +++ b/chrome/browser/ui/cocoa/autofill/autofill_popup_view_cocoa.mm
@@ -197,12 +197,13 @@ textYOffset:(CGFloat)textYOffset { NSColor* nameColor = controller_->IsWarning(index) ? [self warningColor] : [self nameColor]; - NSDictionary* nameAttributes = - [NSDictionary dictionaryWithObjectsAndKeys: - controller_->GetValueFontListForRow(index).GetPrimaryFont(). - GetNativeFont(), - NSFontAttributeName, nameColor, NSForegroundColorAttributeName, - nil]; + NSDictionary* nameAttributes = [NSDictionary + dictionaryWithObjectsAndKeys:controller_->layout_model() + .GetValueFontListForRow(index) + .GetPrimaryFont() + .GetNativeFont(), + NSFontAttributeName, nameColor, + NSForegroundColorAttributeName, nil]; NSSize nameSize = [name sizeWithAttributes:nameAttributes]; x -= rightAlign ? nameSize.width : 0; CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2; @@ -241,13 +242,13 @@ rightAlign:(BOOL)rightAlign bounds:(NSRect)bounds textYOffset:(CGFloat)textYOffset { - NSDictionary* subtextAttributes = - [NSDictionary dictionaryWithObjectsAndKeys: - controller_->GetLabelFontList().GetPrimaryFont().GetNativeFont(), - NSFontAttributeName, - [self subtextColor], - NSForegroundColorAttributeName, - nil]; + NSDictionary* subtextAttributes = [NSDictionary + dictionaryWithObjectsAndKeys:controller_->layout_model() + .GetLabelFontList() + .GetPrimaryFont() + .GetNativeFont(), + NSFontAttributeName, [self subtextColor], + NSForegroundColorAttributeName, nil]; NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; x -= rightAlign ? subtextSize.width : 0; CGFloat y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2;
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc index b40c8e3..c289a8c 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_views.cc
@@ -80,7 +80,7 @@ value_rect.Inset(AutofillPopupLayoutModel::kEndPadding, 0); canvas->DrawStringRectWithFlags( controller_->GetElidedValueAt(index), - controller_->GetValueFontListForRow(index), + controller_->layout_model().GetValueFontListForRow(index), controller_->IsWarning(index) ? kWarningTextColor : kValueTextColor, value_rect, text_align); @@ -111,13 +111,13 @@ // Draw the label text. const int label_width = gfx::GetStringWidth(controller_->GetElidedLabelAt(index), - controller_->GetLabelFontList()); + controller_->layout_model().GetLabelFontList()); if (!is_rtl) x_align_left -= label_width; canvas->DrawStringRectWithFlags( - controller_->GetElidedLabelAt(index), controller_->GetLabelFontList(), - kLabelTextColor, + controller_->GetElidedLabelAt(index), + controller_->layout_model().GetLabelFontList(), kLabelTextColor, gfx::Rect(x_align_left, entry_rect.y(), label_width, entry_rect.height()), text_align); }
diff --git a/content/public/renderer/render_view.h b/content/public/renderer/render_view.h index 00a3074d..6191c19 100644 --- a/content/public/renderer/render_view.h +++ b/content/public/renderer/render_view.h
@@ -38,7 +38,6 @@ namespace content { class RenderFrame; -class RenderWidget; class RenderViewVisitor; struct SSLStatus; struct WebPreferences; @@ -67,9 +66,6 @@ static void ApplyWebPreferences(const WebPreferences& preferences, blink::WebView* web_view); - // Returns the RenderWidget for this RenderView. - virtual RenderWidget* GetWidget() const = 0; - // Returns the main RenderFrame. virtual RenderFrame* GetMainRenderFrame() = 0;
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index 79b007a8..93947fde 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -370,7 +370,7 @@ // Convert the plugin_rect_in_viewport to window coordinates, which is css. WebRect rect_in_css(plugin_rect_in_viewport); blink::WebView* webview = container()->document().frame()->view(); - RenderView::FromWebView(webview)->GetWidget()->convertViewportToWindow( + RenderViewImpl::FromWebView(webview)->GetWidget()->convertViewportToWindow( &rect_in_css); view_rect_ = rect_in_css;
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc index dc7d26a..999a9b39 100644 --- a/content/renderer/render_frame_impl_browsertest.cc +++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -139,7 +139,7 @@ // RenderWidget. TEST_F(RenderFrameImplTest, MAYBE_SubframeWidget) { EXPECT_TRUE(frame_widget()); - EXPECT_NE(frame_widget(), view_->GetWidget()); + EXPECT_NE(frame_widget(), static_cast<RenderViewImpl*>(view_)->GetWidget()); } // Verify a subframe RenderWidget properly processes its viewport being
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 24bd092..f861acb 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h
@@ -179,6 +179,9 @@ // May return NULL when the view is closing. blink::WebView* webview() const; + // Returns the RenderWidget for this RenderView. + RenderWidget* GetWidget() const; + const WebPreferences& webkit_preferences() const { return webkit_preferences_; } @@ -402,7 +405,6 @@ // RenderView implementation ------------------------------------------------- bool Send(IPC::Message* message) override; - RenderWidget* GetWidget() const override; RenderFrameImpl* GetMainRenderFrame() override; int GetRoutingID() const override; gfx::Size GetSize() const override;
diff --git a/content/renderer/render_widget_browsertest.cc b/content/renderer/render_widget_browsertest.cc index 69dd2e4..bf81972 100644 --- a/content/renderer/render_widget_browsertest.cc +++ b/content/renderer/render_widget_browsertest.cc
@@ -11,7 +11,9 @@ class RenderWidgetTest : public RenderViewTest { protected: - RenderWidget* widget() { return view_->GetWidget(); } + RenderWidget* widget() { + return static_cast<RenderViewImpl*>(view_)->GetWidget(); + } void OnResize(const ResizeParams& params) { widget()->OnResize(params);
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index 036f354d..2a054c0 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -30,7 +30,3 @@ # TODO(erikchen) check / generate reference images. self.Fail('Pixel.CSSFilterEffects', ['mac'], bug=581526) self.Fail('Pixel.CSSFilterEffects.NoOverlays', ['mac'], bug=581526) - - # TODO(kbr): remove once expectations for Android have been - # generated using the new naming convention. - self.Fail('*', ['android'], bug=624621)
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index bb90bf65..ddaebfa7 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -147,6 +147,9 @@ self.Fail('conformance2/rendering/uniform-block-buffer-size.html', ['win', 'intel'], bug=628863) + self.Fail('deqp/functional/gles3/fbomultisample*', + ['mac', 'intel'], bug=483282) + # It's unfortunate that these suppressions need to be so broad, but it # looks like the D3D11 device can be lost spontaneously on this # configuration while running basically any test.
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc index 904e900..f7dbe2b 100644 --- a/content/test/layouttest_support.cc +++ b/content/test/layouttest_support.cc
@@ -283,7 +283,9 @@ void SetDeviceColorProfile(RenderView* render_view, const std::string& name) { if (name == "reset") { - render_view->GetWidget()->ResetDeviceColorProfileForTesting(); + static_cast<RenderViewImpl*>(render_view) + ->GetWidget() + ->ResetDeviceColorProfileForTesting(); return; } @@ -415,7 +417,9 @@ color_profile.assign(test.data(), test.data() + test.size()); } - render_view->GetWidget()->SetDeviceColorProfileForTesting(color_profile); + static_cast<RenderViewImpl*>(render_view) + ->GetWidget() + ->SetDeviceColorProfileForTesting(color_profile); } void SetTestBluetoothScanDuration() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error-expected.txt b/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error-expected.txt deleted file mode 100644 index 817588a8..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This test case simulates a decode error after loading meta data of a video. - -EVENT(loadedmetadata) -loaded metadata of media file -EVENT(error) -failed to load media file -EXPECTED (video.networkState == '1') OK -END OF TEST -
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error.html b/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error.html index ca566a3e..cd3f0200 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/video-load-metadata-decode-error.html
@@ -1,41 +1,20 @@ -<html> -<head> - <title>Loading corrupted video with proper metadata</title> - <script src=../../../media-resources/media-file.js></script> - <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956 - (Please avoid writing new tests using video-test.js) --> - <script src=../../../media-resources/video-test.js></script> - <script> - function loadedmetadata(e) - { - consoleWrite("loaded metadata of media file"); - } +<!DOCTYPE html> +<title>This test case simulates a decode error after loading meta data of a video.</title> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../../media-resources/media-file.js"></script> +<video></video> +<script> +async_test(function(t) { + var video = document.querySelector("video"); - function error(e) - { - consoleWrite("failed to load media file"); - testExpected("video.networkState", HTMLMediaElement.NETWORK_IDLE); - endTest(); - } - - function start() - { - findMediaElement(); - - waitForEvent('loadedmetadata', loadedmetadata); - waitForEvent("error", error); - - var movie = findMediaFile("video", "resources/test"); - var type = mimeTypeForExtension(movie.split('.').pop()); - video.src = "video-load-metadata-decode-error.cgi?name=" + movie + "&type=" + type; - video.play(); - } - </script> -</head> -<body onload="start()"> -<video id="video"></video> -<p> -This test case simulates a decode error after loading meta data of a video.<br/><br/> -</p> -</body> -</html> + var watcher = new EventWatcher(t, video, ["loadedmetadata", "error"]); + watcher.wait_for(["loadedmetadata", "error"]).then(t.step_func_done(function() { + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + })); + var movie = findMediaFile("video", "resources/test"); + var type = mimeTypeForExtension(movie.split(".").pop()); + video.src = "video-load-metadata-decode-error.cgi?name=" + movie + "&type=" + type; + video.play(); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend-expected.txt b/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend-expected.txt deleted file mode 100644 index 92697a2a..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -Test that the load eventually suspends and returns to NETWORK_IDLE. - -RUN(video.src = file) -EVENT(loadstart) -EVENT(suspend) -EXPECTED (video.networkState == '1') OK -END OF TEST -
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend.html b/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend.html index 1f531d89..71a7186 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/video-load-suspend.html
@@ -1,33 +1,16 @@ -<html> -<head> -<script src=../../media-resources/media-file.js></script> -<!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956 - (Please avoid writing new tests using video-test.js) --> -<script src=../../media-resources/video-test.js></script> +<!DOCTYPE html> +<title>Test that the load eventually suspends and returns to NETWORK_IDLE.</title> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../../media-resources/media-file.js"></script> +<video></video> <script> - var file = findMediaFile("video", "http://127.0.0.1:8000/resources/test"); - - function init() - { - findMediaElement(); - run("video.src = file"); - waitForEvent('loadstart', onLoadStart); - } - - function onLoadStart() - { - waitForEvent('suspend', onSuspend); - } - - function onSuspend() - { - testExpected("video.networkState", HTMLMediaElement.NETWORK_IDLE, "=="); - endTest(); - } -</script> -</head> -<body onload="init()"> - <p>Test that the load eventually suspends and returns to NETWORK_IDLE.</p> - <video></video> -</body> -</html> +async_test(function(t) { + var video = document.querySelector("video"); + video.src = findMediaFile("video", "http://127.0.0.1:8000/resources/test"); + var watcher = new EventWatcher(t, video, ["loadstart", "suspend"]); + watcher.wait_for(["loadstart", "suspend"]).then(t.step_func_done(function() { + assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE); + })); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice-expected.txt b/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice-expected.txt deleted file mode 100644 index 9d08efb8..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice-expected.txt +++ /dev/null
@@ -1,12 +0,0 @@ -RUN(video.src = file) -EVENT(loadedmetadata) -EVENT(loadeddata) -EVENT(canplay) -EVENT(canplaythrough) -RUN(video.src = file) -EVENT(loadedmetadata) -EVENT(loadeddata) -EVENT(canplay) -EVENT(canplaythrough) -END OF TEST -
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice.html b/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice.html index 6a636ee..f89f1bd 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/video-load-twice.html
@@ -1,35 +1,28 @@ -<html> -<head> -<script src=../../media-resources/media-file.js></script> -<!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956 - (Please avoid writing new tests using video-test.js) --> -<script src=../../media-resources/video-test.js></script> +<!DOCTYPE html> +<title>Test loading video twice.</title> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../../media-resources/media-file.js"></script> +<body> <script> +async_test(function(t) { var file = findMediaFile("video", "http://127.0.0.1:8000/resources/test"); - - function createVideo() { + createAndLoadVideo(false); + function createAndLoadVideo(endTest) { var video = document.createElement("video"); document.body.appendChild(video); - findMediaElement(); - waitForEvent('loadedmetadata'); - waitForEvent('loadeddata'); - waitForEvent('canplay'); - } + var expectedEvents = ["loadedmetadata", "loadeddata", "canplay", "canplaythrough"]; + var watcher = new EventWatcher(t, video, expectedEvents); + watcher.wait_for(expectedEvents).then(t.step_func(function() { + if (endTest) { + t.done(); + } else { + document.body.removeChild(video); + createAndLoadVideo(true); + } + })); - function firstCanPlayThrough() { - document.body.removeChild(video); - createVideo(); - waitForEventOnce('canplaythrough', endTest); - run("video.src = file"); + video.src = file; } - - function init() { - createVideo(); - waitForEventOnce('canplaythrough', firstCanPlayThrough); - run("video.src = file"); - } -</script> -</head> -<body onload="init()"> -</body> -</html> +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass-expected.txt b/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass-expected.txt deleted file mode 100644 index 92f4aed..0000000 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ - -Tests that the media player does not include authorization information. -EVENT(canplay) -END OF TEST -
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass.html b/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass.html index 9014541..34bac02 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/video-load-with-userpass.html
@@ -1,40 +1,29 @@ -<html> - <head> - <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956 - (Please avoid writing new tests using video-test.js) --> - <script src=../../media-resources/video-test.js></script> - <script src=../../media-resources/media-file.js></script> - <script> - function loadMediaFrame() - { - findMediaElement(); +<!DOCTYPE html> +<title>Tests that the media player does not include authorization information.</title> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="../../media-resources/media-file.js"></script> +<body> +<video> + <source></source> +</video> +<script> +async_test(function(t) { + var frame = document.createElement('iframe'); + frame.onload = t.step_func(function() { + var video = document.querySelector('video'); + video.onerror = t.unreached_func(); + video.oncanplay = t.step_func_done(); - var movie = findMediaFile('video', 'test'); - var type = mimeTypeForExtension(movie.split('.').pop()); - var frame = document.createElement('iframe'); - frame.width = 0; - frame.height = 0; - frame.addEventListener('load', function () { - source = document.getElementById('source'); - source.src = 'http://user:pass@127.0.0.1:8080/media/resources/video-check-userpass.php?name=' + movie + '&type=' + type; - source.type = type; + var movie = findMediaFile('video', 'test'); + var type = mimeTypeForExtension(movie.split('.').pop()); + source = document.querySelector('source'); + source.type = type; + source.src = 'http://user:pass@127.0.0.1:8080/media/resources/video-check-userpass.php?name=' + movie + '&type=' + type; + video.load(); + }); - waitForEventAndFail('error'); - waitForEventAndEnd('canplay'); - video.load(); - }); - - frame.src = "data:text/html,<b>test</b>"; - document.body.appendChild(frame); - } - </script> - </head> - - <body onload="loadMediaFrame()"> - <video id="video"> - <source id="source"> - </video> - <br> - Tests that the media player does not include authorization information. - </body> -</html> + frame.src = 'data:text/html,<b>test</b>'; + document.body.appendChild(frame); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index 1540c0f..5ef29d2 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -68,6 +68,8 @@ context.current.transform = frameView.scrollTranslation(); context.current.paintOffset = LayoutPoint(); context.current.clip = frameView.contentClip(); + context.current.renderingContextID = 0; + context.current.shouldFlattenInheritedTransform = true; context.absolutePosition = context.current; context.containerForAbsolutePosition = nullptr; context.fixedPosition = context.current; @@ -115,7 +117,8 @@ LayoutPoint fractionalPaintOffset = LayoutPoint(context.current.paintOffset - roundedPaintOffset); updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::paintOffsetTranslation, &ObjectPaintProperties::setPaintOffsetTranslation>( - object, context, context.current.transform, TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()), FloatPoint3D()); + object, context, context.current.transform, TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()), FloatPoint3D(), + context.current.shouldFlattenInheritedTransform, context.current.renderingContextID); context.current.paintOffset = fractionalPaintOffset; return; } @@ -148,17 +151,38 @@ // The origin is included in the local transform, so leave origin empty. updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::transform, &ObjectPaintProperties::setTransform>( object, context, context.current.transform, TransformationMatrix(transform), FloatPoint3D()); + context.current.renderingContextID = 0; + context.current.shouldFlattenInheritedTransform = false; return; } } else { const ComputedStyle& style = object.styleRef(); - if (object.isBox() && style.hasTransform()) { + if (object.isBox() && (style.hasTransform() || style.preserves3D())) { TransformationMatrix matrix; style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); FloatPoint3D origin = transformOrigin(toLayoutBox(object)); + + unsigned renderingContextID = context.current.renderingContextID; + unsigned renderingContextIDForChildren = 0; + bool flattensInheritedTransform = context.current.shouldFlattenInheritedTransform; + bool childrenFlattenInheritedTransform = true; + + // TODO(trchen): transform-style should only be respected if a PaintLayer is + // created. + if (style.preserves3D()) { + // If a node with transform-style: preserve-3d does not exist in an + // existing rendering context, it establishes a new one. + if (!renderingContextID) + renderingContextID = PtrHash<const LayoutObject>::hash(&object); + renderingContextIDForChildren = renderingContextID; + childrenFlattenInheritedTransform = false; + } + updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::transform, &ObjectPaintProperties::setTransform>( - object, context, context.current.transform, matrix, origin); + object, context, context.current.transform, matrix, origin, flattensInheritedTransform, renderingContextID); + context.current.renderingContextID = renderingContextIDForChildren; + context.current.shouldFlattenInheritedTransform = childrenFlattenInheritedTransform; return; } } @@ -275,9 +299,14 @@ return; } + // The perspective node must not flatten (else nothing will get + // perspective), but it should still extend the rendering context as most + // transform nodes do. + TransformationMatrix matrix = TransformationMatrix().applyPerspective(style.perspective()); FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) + toLayoutSize(context.current.paintOffset); updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::perspective, &ObjectPaintProperties::setPerspective>( - object, context, context.current.transform, TransformationMatrix().applyPerspective(style.perspective()), origin); + object, context, context.current.transform, matrix, origin, context.current.shouldFlattenInheritedTransform, context.current.renderingContextID); + context.current.shouldFlattenInheritedTransform = false; } void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) @@ -298,6 +327,8 @@ updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::svgLocalToBorderBoxTransform, &ObjectPaintProperties::setSvgLocalToBorderBoxTransform>( object, context, context.current.transform, transformToBorderBox, FloatPoint3D()); + context.current.shouldFlattenInheritedTransform = false; + context.current.renderingContextID = 0; } void PaintPropertyTreeBuilder::updateScrollTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) @@ -310,7 +341,8 @@ if (!scrollOffset.isZero() || layer->scrollsOverflow()) { TransformationMatrix matrix = TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.height()); updateOrCreatePaintProperty<TransformPaintPropertyNode, &ObjectPaintProperties::scrollTranslation, &ObjectPaintProperties::setScrollTranslation>( - object, context, context.current.transform, matrix, FloatPoint3D()); + object, context, context.current.transform, matrix, FloatPoint3D(), context.current.shouldFlattenInheritedTransform, context.current.renderingContextID); + context.current.shouldFlattenInheritedTransform = false; return; } } @@ -412,8 +444,6 @@ updateLocalBorderBoxContext(object, context); updateScrollbarPaintOffset(object, context); updateOverflowClip(object, context); - // TODO(trchen): Insert flattening transform here, as specified by - // http://www.w3.org/TR/css3-transforms/#transform-style-property updatePerspective(object, context); updateSvgLocalToBorderBoxTransform(object, context); updateScrollTranslation(object, context);
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h index 72a21f3d..9055a1f 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -30,6 +30,14 @@ // the space with its own layout location. TransformPaintPropertyNode* transform = nullptr; LayoutPoint paintOffset; + // Whether newly created children should flatten their inherited transform + // (equivalently, draw into the plane of their parent). Should generally + // be updated whenever |transform| is; flattening only needs to happen + // to immediate children. + bool shouldFlattenInheritedTransform = false; + // Rendering context for 3D sorting. See + // TransformPaintPropertyNode::renderingContextID. + unsigned renderingContextID = 0; // The clip node describes the accumulated raster clip for the current subtree. // Note that the computed raster region in canvas space for a clip node is independent from // the transform and paint offset above. Also the actual raster region may be affected
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index 9979fdd..d395791 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -1109,6 +1109,176 @@ EXPECT_EQ(svgWithTransformProperties->transform(), rectWithTransformProperties->transform()->parent()); } +TEST_F(PaintPropertyTreeBuilderTest, NoRenderingContextByDefault) +{ + setBodyInnerHTML("<div style=\"transform: translateZ(0)\"></div>"); + + ObjectPaintProperties* properties = document().body()->firstChild()->layoutObject()->objectPaintProperties(); + ASSERT_TRUE(properties->transform()); + EXPECT_FALSE(properties->transform()->hasRenderingContext()); +} + +TEST_F(PaintPropertyTreeBuilderTest, Preserve3DCreatesSharedRenderingContext) +{ + setBodyInnerHTML( + "<div style=\"transform-style: preserve-3d\">" + " <div id=\"a\" style=\"transform: translateZ(0)\"></div>" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + "</div>"); + + ObjectPaintProperties* aProperties = document().getElementById("a")->layoutObject()->objectPaintProperties(); + ObjectPaintProperties* bProperties = document().getElementById("b")->layoutObject()->objectPaintProperties(); + ASSERT_TRUE(aProperties->transform() && bProperties->transform()); + EXPECT_NE(aProperties->transform(), bProperties->transform()); + EXPECT_TRUE(aProperties->transform()->hasRenderingContext()); + EXPECT_TRUE(bProperties->transform()->hasRenderingContext()); + EXPECT_EQ(aProperties->transform()->renderingContextID(), bProperties->transform()->renderingContextID()); +} + +TEST_F(PaintPropertyTreeBuilderTest, FlatTransformStyleEndsRenderingContext) +{ + setBodyInnerHTML( + "<div style=\"transform-style: preserve-3d\">" + " <div id=\"a\" style=\"transform: translateZ(0)\">" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + " </div>" + "</div>"); + + ASSERT_FALSE(document().getElementById("a")->layoutObject()->styleRef().preserves3D()); + ObjectPaintProperties* aProperties = document().getElementById("a")->layoutObject()->objectPaintProperties(); + ObjectPaintProperties* bProperties = document().getElementById("b")->layoutObject()->objectPaintProperties(); + ASSERT_TRUE(aProperties->transform() && bProperties->transform()); + + // #a should participate in a rendering context (due to its parent), but its + // child #b should not. + EXPECT_TRUE(aProperties->transform()->hasRenderingContext()); + EXPECT_FALSE(bProperties->transform()->hasRenderingContext()); +} + +TEST_F(PaintPropertyTreeBuilderTest, NestedRenderingContexts) +{ + setBodyInnerHTML( + "<div style=\"transform-style: preserve-3d\">" + " <div id=\"a\" style=\"transform: translateZ(0)\">" + " <div style=\"transform-style: preserve-3d\">" + " <div id=\"b\" style=\"transform: translateZ(0)\">" + " </div>" + " </div>" + "</div>"); + + ASSERT_FALSE(document().getElementById("a")->layoutObject()->styleRef().preserves3D()); + ObjectPaintProperties* aProperties = document().getElementById("a")->layoutObject()->objectPaintProperties(); + ObjectPaintProperties* bProperties = document().getElementById("b")->layoutObject()->objectPaintProperties(); + ASSERT_TRUE(aProperties->transform() && bProperties->transform()); + + // #a should participate in a rendering context (due to its parent). Its + // child does preserve 3D, but since #a does not, #a's rendering context is + // not passed on to its children. Thus #b ends up in a separate rendering + // context rooted at its parent. + EXPECT_TRUE(aProperties->transform()->hasRenderingContext()); + EXPECT_TRUE(bProperties->transform()->hasRenderingContext()); + EXPECT_NE(aProperties->transform()->renderingContextID(), bProperties->transform()->renderingContextID()); +} + +// Returns true if the first node has the second as an ancestor. +static bool nodeHasAncestor(const TransformPaintPropertyNode* node, const TransformPaintPropertyNode* ancestor) +{ + while (node) { + if (node == ancestor) + return true; + node = node->parent(); + } + return false; +} + +// Returns true if some node will flatten the transform due to |node| before it +// is inherited by |node| (including if node->flattensInheritedTransform()). +static bool someNodeFlattensTransform(const TransformPaintPropertyNode* node, const TransformPaintPropertyNode* ancestor) +{ + while (node != ancestor) { + if (node->flattensInheritedTransform()) + return true; + node = node->parent(); + } + return false; +} + +TEST_F(PaintPropertyTreeBuilderTest, FlatTransformStylePropagatesToChildren) +{ + setBodyInnerHTML( + "<div id=\"a\" style=\"transform: translateZ(0); transform-style: flat\">" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + "</div>"); + + const auto* aTransform = document().getElementById("a")->layoutObject()->objectPaintProperties()->transform(); + ASSERT_TRUE(aTransform); + const auto* bTransform = document().getElementById("b")->layoutObject()->objectPaintProperties()->transform(); + ASSERT_TRUE(bTransform); + ASSERT_TRUE(nodeHasAncestor(bTransform, aTransform)); + + // Some node must flatten the inherited transform from #a before it reaches + // #b's transform. + EXPECT_TRUE(someNodeFlattensTransform(bTransform, aTransform)); +} + +TEST_F(PaintPropertyTreeBuilderTest, Preserve3DTransformStylePropagatesToChildren) +{ + setBodyInnerHTML( + "<div id=\"a\" style=\"transform: translateZ(0); transform-style: preserve-3d\">" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + "</div>"); + + const auto* aTransform = document().getElementById("a")->layoutObject()->objectPaintProperties()->transform(); + ASSERT_TRUE(aTransform); + const auto* bTransform = document().getElementById("b")->layoutObject()->objectPaintProperties()->transform(); + ASSERT_TRUE(bTransform); + ASSERT_TRUE(nodeHasAncestor(bTransform, aTransform)); + + // No node may flatten the inherited transform from #a before it reaches + // #b's transform. + EXPECT_FALSE(someNodeFlattensTransform(bTransform, aTransform)); +} + +TEST_F(PaintPropertyTreeBuilderTest, PerspectiveIsNotFlattened) +{ + // It's necessary to make nodes from the one that applies perspective to + // ones that combine with it preserve 3D. Otherwise, the perspective doesn't + // do anything. + setBodyInnerHTML( + "<div id=\"a\" style=\"perspective: 800px\">" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + "</div>"); + + ObjectPaintProperties* aProperties = document().getElementById("a")->layoutObject()->objectPaintProperties(); + ObjectPaintProperties* bProperties = document().getElementById("b")->layoutObject()->objectPaintProperties(); + const TransformPaintPropertyNode* aPerspective = aProperties->perspective(); + ASSERT_TRUE(aPerspective); + const TransformPaintPropertyNode* bTransform = bProperties->transform(); + ASSERT_TRUE(bTransform); + ASSERT_TRUE(nodeHasAncestor(bTransform, aPerspective)); + EXPECT_FALSE(someNodeFlattensTransform(bTransform, aPerspective)); +} + +TEST_F(PaintPropertyTreeBuilderTest, PerspectiveDoesNotEstablishRenderingContext) +{ + // It's necessary to make nodes from the one that applies perspective to + // ones that combine with it preserve 3D. Otherwise, the perspective doesn't + // do anything. + setBodyInnerHTML( + "<div id=\"a\" style=\"perspective: 800px\">" + " <div id=\"b\" style=\"transform: translateZ(0)\"></div>" + "</div>"); + + ObjectPaintProperties* aProperties = document().getElementById("a")->layoutObject()->objectPaintProperties(); + ObjectPaintProperties* bProperties = document().getElementById("b")->layoutObject()->objectPaintProperties(); + const TransformPaintPropertyNode* aPerspective = aProperties->perspective(); + ASSERT_TRUE(aPerspective); + EXPECT_FALSE(aPerspective->hasRenderingContext()); + const TransformPaintPropertyNode* bTransform = bProperties->transform(); + ASSERT_TRUE(bTransform); + EXPECT_FALSE(bTransform->hasRenderingContext()); +} + TEST_F(PaintPropertyTreeBuilderTest, CachedProperties) { setBodyInnerHTML(
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index 5e552c2b..da3c470 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -415,6 +415,8 @@ compositorNode.post_local.matrix().setTranslate( origin.x(), origin.y(), origin.z()); compositorNode.needs_local_transform_update = true; + compositorNode.flattens_inherited_transform = transformNode->flattensInheritedTransform(); + compositorNode.sorting_context_id = transformNode->renderingContextID(); m_rootLayer->AddChild(dummyLayer); dummyLayer->SetTransformTreeIndex(id); @@ -585,6 +587,10 @@ layer->SetEffectTreeIndex(effectId); layer->SetScrollTreeIndex(kRealRootNodeId); + // TODO(jbroman): This probably shouldn't be necessary, but it is still + // queried by RenderSurfaceImpl. + layer->Set3dSortingContextId(host->property_trees()->transform_tree.Node(transformId)->sorting_context_id); + if (m_extraDataForTestingEnabled) m_extraDataForTesting->contentLayers.append(layer); }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp index 3e51ec8..9ac8a06c 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -8,10 +8,12 @@ #include "base/threading/thread_task_runner_handle.h" #include "cc/layers/layer.h" #include "cc/test/fake_output_surface.h" +#include "cc/test/geometry_test_utils.h" #include "cc/trees/clip_node.h" #include "cc/trees/effect_node.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_settings.h" +#include "cc/trees/transform_node.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/graphics/paint/EffectPaintPropertyNode.h" #include "platform/graphics/paint/PaintArtifact.h" @@ -416,6 +418,11 @@ return *m_webLayerTreeView->layerTreeHost()->property_trees(); } + const cc::TransformNode& transformNode(const cc::Layer* layer) + { + return *propertyTrees().transform_tree.Node(layer->transform_tree_index()); + } + void update(const PaintArtifact& artifact) { PaintArtifactCompositorTest::update(artifact); @@ -527,6 +534,119 @@ contentLayerAt(1)->transform_tree_index()); } +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, FlattensInheritedTransform) +{ + for (bool transformIsFlattened : { true, false }) { + SCOPED_TRACE(transformIsFlattened); + + // The flattens_inherited_transform bit corresponds to whether the _parent_ + // transform node flattens the transform. This is because Blink's notion of + // flattening determines whether content within the node's local transform + // is flattened, while cc's notion applies in the parent's coordinate space. + RefPtr<TransformPaintPropertyNode> transform1 = TransformPaintPropertyNode::create( + nullptr, TransformationMatrix(), FloatPoint3D()); + RefPtr<TransformPaintPropertyNode> transform2 = TransformPaintPropertyNode::create( + transform1, TransformationMatrix().rotate3d(0, 45, 0), FloatPoint3D()); + RefPtr<TransformPaintPropertyNode> transform3 = TransformPaintPropertyNode::create( + transform2, TransformationMatrix().rotate3d(0, 45, 0), FloatPoint3D(), + transformIsFlattened); + + TestPaintArtifact artifact; + artifact.chunk(transform3, nullptr, nullptr) + .rectDrawing(FloatRect(0, 0, 300, 200), Color::white); + update(artifact.build()); + + ASSERT_EQ(1u, contentLayerCount()); + const cc::Layer* layer = contentLayerAt(0); + EXPECT_THAT(layer->GetPicture(), + Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::white))); + + // The leaf transform node should flatten its inherited transform node + // if and only if the intermediate rotation transform in the Blink tree + // flattens. + const cc::TransformNode* transformNode3 = propertyTrees().transform_tree.Node(layer->transform_tree_index()); + EXPECT_EQ(transformIsFlattened, transformNode3->flattens_inherited_transform); + + // Given this, we should expect the correct screen space transform for + // each case. If the transform was flattened, we should see it getting + // an effective horizontal scale of 1/sqrt(2) each time, thus it gets + // half as wide. If the transform was not flattened, we should see an + // empty rectangle (as the total 90 degree rotation makes it + // perpendicular to the viewport). + gfx::RectF rect(0, 0, 100, 100); + layer->screen_space_transform().TransformRect(&rect); + if (transformIsFlattened) + EXPECT_FLOAT_RECT_EQ(gfx::RectF(0, 0, 50, 100), rect); + else + EXPECT_TRUE(rect.IsEmpty()); + } +} + +TEST_F(PaintArtifactCompositorTestWithPropertyTrees, SortingContextID) +{ + // Has no 3D rendering context. + RefPtr<TransformPaintPropertyNode> transform1 = TransformPaintPropertyNode::create( + nullptr, TransformationMatrix(), FloatPoint3D()); + // Establishes a 3D rendering context. + RefPtr<TransformPaintPropertyNode> transform2 = TransformPaintPropertyNode::create( + transform1, TransformationMatrix(), FloatPoint3D(), false, 1); + // Extends the 3D rendering context of transform2. + RefPtr<TransformPaintPropertyNode> transform3 = TransformPaintPropertyNode::create( + transform2, TransformationMatrix(), FloatPoint3D(), false, 1); + // Establishes a 3D rendering context distinct from transform2. + RefPtr<TransformPaintPropertyNode> transform4 = TransformPaintPropertyNode::create( + transform2, TransformationMatrix(), FloatPoint3D(), false, 2); + + TestPaintArtifact artifact; + artifact.chunk(transform1, nullptr, dummyRootEffect()) + .rectDrawing(FloatRect(0, 0, 300, 200), Color::white); + artifact.chunk(transform2, nullptr, dummyRootEffect()) + .rectDrawing(FloatRect(0, 0, 300, 200), Color::lightGray); + artifact.chunk(transform3, nullptr, dummyRootEffect()) + .rectDrawing(FloatRect(0, 0, 300, 200), Color::darkGray); + artifact.chunk(transform4, nullptr, dummyRootEffect()) + .rectDrawing(FloatRect(0, 0, 300, 200), Color::black); + update(artifact.build()); + + ASSERT_EQ(4u, contentLayerCount()); + + // The white layer is not 3D sorted. + const cc::Layer* whiteLayer = contentLayerAt(0); + EXPECT_THAT(whiteLayer->GetPicture(), + Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::white))); + int whiteSortingContextId = transformNode(whiteLayer).sorting_context_id; + EXPECT_EQ(whiteLayer->sorting_context_id(), whiteSortingContextId); + EXPECT_EQ(0, whiteSortingContextId); + + // The light gray layer is 3D sorted. + const cc::Layer* lightGrayLayer = contentLayerAt(1); + EXPECT_THAT(lightGrayLayer->GetPicture(), + Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::lightGray))); + int lightGraySortingContextId = transformNode(lightGrayLayer).sorting_context_id; + EXPECT_EQ(lightGrayLayer->sorting_context_id(), lightGraySortingContextId); + EXPECT_NE(0, lightGraySortingContextId); + + // The dark gray layer is 3D sorted with the light gray layer, but has a + // separate transform node. + const cc::Layer* darkGrayLayer = contentLayerAt(2); + EXPECT_THAT(darkGrayLayer->GetPicture(), + Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::darkGray))); + int darkGraySortingContextId = transformNode(darkGrayLayer).sorting_context_id; + EXPECT_EQ(darkGrayLayer->sorting_context_id(), darkGraySortingContextId); + EXPECT_EQ(lightGraySortingContextId, darkGraySortingContextId); + EXPECT_NE(lightGrayLayer->transform_tree_index(), darkGrayLayer->transform_tree_index()); + + // The black layer is 3D sorted, but in a separate context from the previous + // layers. + const cc::Layer* blackLayer = contentLayerAt(3); + EXPECT_THAT(blackLayer->GetPicture(), + Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::black))); + int blackSortingContextId = transformNode(blackLayer).sorting_context_id; + EXPECT_EQ(blackLayer->sorting_context_id(), blackSortingContextId); + EXPECT_NE(0, blackSortingContextId); + EXPECT_NE(lightGraySortingContextId, blackSortingContextId); +} + TEST_F(PaintArtifactCompositorTestWithPropertyTrees, OneClip) { RefPtr<ClipPaintPropertyNode> clip = ClipPaintPropertyNode::create(
diff --git a/third_party/WebKit/Source/platform/graphics/paint/README.md b/third_party/WebKit/Source/platform/graphics/paint/README.md index 009a752..1bcf259 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/README.md +++ b/third_party/WebKit/Source/platform/graphics/paint/README.md
@@ -53,6 +53,12 @@ transform origin will rotate the plane about that point) * a pointer to the parent node, which defines the coordinate space relative to which the above should be interpreted +* a boolean indicating whether the transform should be projected into the plane + of its parent (i.e., whether the total transform inherited from its parent + should be flattened before this node's transform is applied and propagated to + children) +* an integer rendering context ID; content whose transform nodes share a + rendering context ID should sort together The parent node pointers link the transform nodes in a hierarchy (the *transform tree*), which defines how the transform for any painted content can be @@ -66,9 +72,11 @@ order to create the illusion of depth. *** -*** aside -TODO(jbroman): Explain flattening, etc., once it exists in the paint properties. -*** +Note that, even though CSS does not permit it in the DOM, the transform tree can +have nodes whose children do not flatten their inherited transform and +participate in no 3D rendering context. For example, not flattening is necessary +to preserve the 3D character of the perspective transform, but this does not +imply any 3D sorting. ### Clips
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h index 1481e60..1020a207 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h +++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
@@ -21,16 +21,23 @@ // for the root. class PLATFORM_EXPORT TransformPaintPropertyNode : public RefCounted<TransformPaintPropertyNode> { public: - static PassRefPtr<TransformPaintPropertyNode> create(PassRefPtr<TransformPaintPropertyNode> parent, const TransformationMatrix& matrix, const FloatPoint3D& origin) + static PassRefPtr<TransformPaintPropertyNode> create( + PassRefPtr<TransformPaintPropertyNode> parent, + const TransformationMatrix& matrix, + const FloatPoint3D& origin, + bool flattensInheritedTransform = false, + unsigned renderingContextID = 0) { - return adoptRef(new TransformPaintPropertyNode(parent, matrix, origin)); + return adoptRef(new TransformPaintPropertyNode(matrix, origin, parent, flattensInheritedTransform, renderingContextID)); } - void update(PassRefPtr<TransformPaintPropertyNode> parent, const TransformationMatrix& matrix, const FloatPoint3D& origin) + void update(PassRefPtr<TransformPaintPropertyNode> parent, const TransformationMatrix& matrix, const FloatPoint3D& origin, bool flattensInheritedTransform = false, unsigned renderingContextID = 0) { m_parent = parent; m_matrix = matrix; m_origin = origin; + m_flattensInheritedTransform = flattensInheritedTransform; + m_renderingContextID = renderingContextID; } const TransformationMatrix& matrix() const { return m_matrix; } @@ -40,13 +47,36 @@ // is the root transform. TransformPaintPropertyNode* parent() const { return m_parent.get(); } -private: - TransformPaintPropertyNode(PassRefPtr<TransformPaintPropertyNode> parent, const TransformationMatrix& matrix, const FloatPoint3D& origin) - : m_parent(parent), m_matrix(matrix), m_origin(origin) { } + // If true, content with this transform node (or its descendant) appears in + // the plane of its parent. This is implemented by flattening the total + // accumulated transform from its ancestors. + bool flattensInheritedTransform() const { return m_flattensInheritedTransform; } - RefPtr<TransformPaintPropertyNode> m_parent; + // Content whose transform nodes have a common rendering context ID are 3D + // sorted. If this is 0, content will not be 3D sorted. + unsigned renderingContextID() const { return m_renderingContextID; } + bool hasRenderingContext() const { return m_renderingContextID; } + +private: + TransformPaintPropertyNode( + const TransformationMatrix& matrix, + const FloatPoint3D& origin, + PassRefPtr<TransformPaintPropertyNode> parent, + bool flattensInheritedTransform, + unsigned renderingContextID) + : m_matrix(matrix) + , m_origin(origin) + , m_parent(parent) + , m_flattensInheritedTransform(flattensInheritedTransform) + , m_renderingContextID(renderingContextID) + { + } + TransformationMatrix m_matrix; FloatPoint3D m_origin; + RefPtr<TransformPaintPropertyNode> m_parent; + bool m_flattensInheritedTransform; + unsigned m_renderingContextID; }; // Redeclared here to avoid ODR issues.
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py index d7b080a7..a4f8dfb 100644 --- a/tools/perf/benchmarks/system_health.py +++ b/tools/perf/benchmarks/system_health.py
@@ -83,6 +83,10 @@ take_memory_measurement=True) @classmethod + def ShouldTearDownStateAfterEachStoryRun(cls): + return True + + @classmethod def Name(cls): return 'system_health.memory_%s' % cls.PLATFORM