diff --git a/DEPS b/DEPS index 623814e..e7d245f6 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # 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': '0396434adf4f7cdc1880046181d72167207f8ca5', + 'skia_revision': 'dbc8eeb592123619d9c5bb4b6c6225b9fd45d03b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'd2c38959a71552b4e39e4d9ee3a7cae2c84e5843', + 'v8_revision': '6b70e6608fb664588720103720a9066bccfe181e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS index 484e25b..3a0cdb3a0 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -108,6 +108,11 @@ 'arc_auth': { 'filepath': 'chrome/browser/chromeos/arc/arc_auth' }, + 'arc_kiosk': { + 'filepath': 'chrome/browser/chromeos/app_mode/arc/'\ + '|components/arc/kiosk/'\ + '|arc_kiosk' + }, 'arc_net': { 'filepath': 'components/arc/net/', }, @@ -1529,6 +1534,7 @@ 'lhchavez+watch@chromium.org', 'yusukes+watch@chromium.org'], 'arc_auth': ['khmel+watch@chromium.org'], + 'arc_kiosk': ['poromov+watch@chromium.org'], 'arc_net': ['abhishekbh@chromium.org', 'cernekee@chromium.org', 'snanda@chromium.org'],
diff --git a/ash/common/system/status_area_widget_delegate.cc b/ash/common/system/status_area_widget_delegate.cc index 920c171e6..26c3ddc3b 100644 --- a/ash/common/system/status_area_widget_delegate.cc +++ b/ash/common/system/status_area_widget_delegate.cc
@@ -146,14 +146,10 @@ views::ColumnSet* columns = layout->AddColumnSet(0); if (IsHorizontalAlignment(alignment_)) { - bool is_first_visible_child = true; for (int c = child_count() - 1; c >= 0; --c) { views::View* child = child_at(c); if (!child->visible()) continue; - if (!is_first_visible_child) - columns->AddPaddingColumn(0, GetTrayConstant(TRAY_SPACING)); - is_first_visible_child = false; columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 0, /* resize percent */ views::GridLayout::USE_PREF, 0, 0); @@ -168,14 +164,10 @@ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 0, /* resize percent */ views::GridLayout::USE_PREF, 0, 0); - bool is_first_visible_child = true; for (int c = child_count() - 1; c >= 0; --c) { views::View* child = child_at(c); if (!child->visible()) continue; - if (!is_first_visible_child) - layout->AddPaddingRow(0, GetTrayConstant(TRAY_SPACING)); - is_first_visible_child = false; layout->StartRow(0, 0); layout->AddView(child); }
diff --git a/ash/common/system/tray/system_tray_item.cc b/ash/common/system/tray/system_tray_item.cc index 164a0e4..2d34391 100644 --- a/ash/common/system/tray/system_tray_item.cc +++ b/ash/common/system/tray/system_tray_item.cc
@@ -42,16 +42,11 @@ void SystemTrayItem::DestroyNotificationView() {} void SystemTrayItem::TransitionDetailedView() { - const int transition_delay = - GetTrayConstant(TRAY_POPUP_TRANSITION_TO_DETAILED_DELAY); - if (transition_delay <= 0) { - DoTransitionToDetailedView(); - return; - } - transition_delay_timer_.reset(new base::OneShotTimer()); - transition_delay_timer_->Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(transition_delay), this, - &SystemTrayItem::DoTransitionToDetailedView); + transition_delay_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), + base::Bind(&SystemTray::ShowDetailedView, base::Unretained(system_tray()), + this, 0, true, BUBBLE_USE_EXISTING)); } void SystemTrayItem::UpdateAfterLoginStatusChange(LoginStatus status) {} @@ -84,9 +79,4 @@ return true; } -void SystemTrayItem::DoTransitionToDetailedView() { - transition_delay_timer_.reset(); - system_tray()->ShowDetailedView(this, 0, true, BUBBLE_USE_EXISTING); -} - } // namespace ash
diff --git a/ash/common/system/tray/system_tray_item.h b/ash/common/system/tray/system_tray_item.h index 2e7ca00..68f1966 100644 --- a/ash/common/system/tray/system_tray_item.h +++ b/ash/common/system/tray/system_tray_item.h
@@ -11,10 +11,7 @@ #include "ash/common/login_status.h" #include "ash/public/cpp/shelf_types.h" #include "base/macros.h" - -namespace base { -class OneShotTimer; -} // namespace base +#include "base/timer/timer.h" namespace views { class View; @@ -154,9 +151,6 @@ void set_restore_focus(bool restore_focus) { restore_focus_ = restore_focus; } private: - // Actually transitions to the detailed view. - void DoTransitionToDetailedView(); - // Accesses uma_type(). friend class SystemTrayBubble; @@ -167,7 +161,7 @@ bool restore_focus_; // Used to delay the transition to the detailed view. - std::unique_ptr<base::OneShotTimer> transition_delay_timer_; + base::OneShotTimer transition_delay_timer_; DISALLOW_COPY_AND_ASSIGN(SystemTrayItem); };
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc index a08b49e..dd28557b 100644 --- a/ash/common/system/tray/tray_constants.cc +++ b/ash/common/system/tray/tray_constants.cc
@@ -46,6 +46,9 @@ const int kTrayPopupPaddingBetweenItems = 10; const int kTrayPopupButtonEndMargin = 10; const int kTrayPopupLabelHorizontalPadding = 4; + +const int kTrayDetailedViewTransitionDelayMs = 100; + const int kTrayPopupSliderPaddingMD = 16; const int kTrayPopupLabelRightPadding = 8; @@ -107,7 +110,6 @@ int GetTrayConstant(TrayConstant constant) { const int kTrayItemHeightLegacy[] = {38, kTrayItemSize, kTrayItemSize}; - const int kTraySpacing[] = {4, 0, 0}; const int kTrayPaddingFromEdgeOfShelf[] = {3, 3, 3}; const int kTrayPopupItemMinHeight[] = {46, 48, 48}; const int kTrayPopupItemMaxHeight[] = {138, 144, 144}; @@ -116,11 +118,8 @@ const int kTrayPopupItemMoreImageSize[] = {25, kMenuIconSize, kMenuIconSize}; const int kTrayPopupItemMoreRegionHorizontalInset[] = {10, 10, 10}; const int kTrayPopupItemLeftInset[] = {0, 4, 4}; - const int kTrayPopupItemRightInset[] = {0, 0, 0}; const int kTrayPopupItemMinStartWidth[] = {46, 48, 48}; const int kTrayPopupItemMinEndWidth[] = {40, 40, 40}; - const int kTrayPopupTransitionToDefaultViewDelayMs[] = {0, 100, 100}; - const int kTrayPopupTransitionToDetailedViewDelayMs[] = {0, 100, 100}; const int kVirtualKeyboardButtonSize[] = {39, kTrayItemSize, kTrayItemSize}; const int kTrayImeMenuIcon[] = {40, kTrayItemSize, kTrayItemSize}; const int kTrayImageItemPadding[] = {1, 3, 3}; @@ -131,8 +130,6 @@ switch (constant) { case TRAY_ITEM_HEIGHT_LEGACY: return kTrayItemHeightLegacy[mode]; - case TRAY_SPACING: - return kTraySpacing[mode]; case TRAY_PADDING_FROM_EDGE_OF_SHELF: return kTrayPaddingFromEdgeOfShelf[mode]; case TRAY_POPUP_ITEM_MIN_HEIGHT: @@ -147,16 +144,10 @@ return kTrayPopupItemMoreRegionHorizontalInset[mode]; case TRAY_POPUP_ITEM_LEFT_INSET: return kTrayPopupItemLeftInset[mode]; - case TRAY_POPUP_ITEM_RIGHT_INSET: - return kTrayPopupItemRightInset[mode]; case TRAY_POPUP_ITEM_MIN_START_WIDTH: return kTrayPopupItemMinStartWidth[mode]; case TRAY_POPUP_ITEM_MIN_END_WIDTH: return kTrayPopupItemMinEndWidth[mode]; - case TRAY_POPUP_TRANSITION_TO_DEFAULT_DELAY: - return kTrayPopupTransitionToDefaultViewDelayMs[mode]; - case TRAY_POPUP_TRANSITION_TO_DETAILED_DELAY: - return kTrayPopupTransitionToDetailedViewDelayMs[mode]; case VIRTUAL_KEYBOARD_BUTTON_SIZE: return kVirtualKeyboardButtonSize[mode]; case TRAY_IME_MENU_ICON:
diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h index 29665ae7..87f6175b 100644 --- a/ash/common/system/tray/tray_constants.h +++ b/ash/common/system/tray/tray_constants.h
@@ -48,6 +48,10 @@ // in the system menu. extern const int kTrayPopupLabelHorizontalPadding; +// When transitioning between a detailed and a default view, this delay is used +// before the transition starts. +ASH_EXPORT extern const int kTrayDetailedViewTransitionDelayMs; + // Padding used to adjust the slider position in volume row and brightness // row horizontally. extern const int kTrayPopupSliderPaddingMD; @@ -143,9 +147,6 @@ // borders on tray items. TRAY_ITEM_HEIGHT_LEGACY, - // Padding between items in the status tray area. - TRAY_SPACING, - // Padding between the edge of shelf and the item in status tray area. TRAY_PADDING_FROM_EDGE_OF_SHELF, @@ -168,21 +169,12 @@ // The left inset for all tray system menu rows. TRAY_POPUP_ITEM_LEFT_INSET, - // The right inset for all tray system menu rows. - TRAY_POPUP_ITEM_RIGHT_INSET, - // The minimum default width for the left container of the system menu rows. TRAY_POPUP_ITEM_MIN_START_WIDTH, // The minimum default width for the right container of the system menu rows. TRAY_POPUP_ITEM_MIN_END_WIDTH, - // Duration to delay transitions to the default view. - TRAY_POPUP_TRANSITION_TO_DEFAULT_DELAY, - - // Duration to delay transitions to the detailed view. - TRAY_POPUP_TRANSITION_TO_DETAILED_DELAY, - // The width and height of the virtual keyboard button in the status tray // area. For non-MD, adjustments are made to the button dimensions based on // the shelf orientation, so this constant does not specify the true
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc index b7749501..4cf0f97b 100644 --- a/ash/common/system/tray/tray_details_view.cc +++ b/ash/common/system/tray/tray_details_view.cc
@@ -15,7 +15,6 @@ #include "ash/common/system/tray/tri_view.h" #include "base/containers/adapters.h" #include "base/memory/ptr_util.h" -#include "base/timer/timer.h" #include "grit/ash_strings.h" #include "third_party/skia/include/core/SkDrawLooper.h" #include "ui/base/resource/resource_bundle.h" @@ -458,22 +457,13 @@ return; } - const int transition_delay = - GetTrayConstant(TRAY_POPUP_TRANSITION_TO_DEFAULT_DELAY); - if (transition_delay <= 0) { - DoTransitionToDefaultView(); - return; - } - - transition_delay_timer_.reset(new base::OneShotTimer()); - transition_delay_timer_->Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(transition_delay), this, - &TrayDetailsView::DoTransitionToDefaultView); + transition_delay_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), + this, &TrayDetailsView::DoTransitionToDefaultView); } void TrayDetailsView::DoTransitionToDefaultView() { - transition_delay_timer_.reset(); - // Cache pointer to owner in this function scope. TrayDetailsView will be // deleted after called ShowDefaultView. SystemTrayItem* owner = owner_;
diff --git a/ash/common/system/tray/tray_details_view.h b/ash/common/system/tray/tray_details_view.h index d7046e7..2828763 100644 --- a/ash/common/system/tray/tray_details_view.h +++ b/ash/common/system/tray/tray_details_view.h
@@ -12,14 +12,10 @@ #include "ash/common/system/tray/tray_constants.h" #include "ash/common/system/tray/view_click_listener.h" #include "base/macros.h" -#include "grit/ash_strings.h" +#include "base/timer/timer.h" #include "ui/views/controls/button/button.h" #include "ui/views/view.h" -namespace base { -class OneShotTimer; -} // namespace base - namespace views { class BoxLayout; class CustomButton; @@ -139,7 +135,7 @@ views::Button* back_button_; // Used to delay the transition to the default view. - std::unique_ptr<base::OneShotTimer> transition_delay_timer_; + base::OneShotTimer transition_delay_timer_; DISALLOW_COPY_AND_ASSIGN(TrayDetailsView); };
diff --git a/ash/common/system/tray/tray_details_view_unittest.cc b/ash/common/system/tray/tray_details_view_unittest.cc index a62f8b6..e8543c4 100644 --- a/ash/common/system/tray/tray_details_view_unittest.cc +++ b/ash/common/system/tray/tray_details_view_unittest.cc
@@ -126,8 +126,8 @@ void TransitionFromDetailedToDefaultView(TestDetailsView* detailed) { detailed->TransitionToDefaultView(); - scoped_task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds( - GetTrayConstant(TRAY_POPUP_TRANSITION_TO_DEFAULT_DELAY))); + scoped_task_runner_->FastForwardBy( + base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs)); } void FocusBackButton(TestDetailsView* detailed) {
diff --git a/ash/common/system/tray/tray_popup_utils.cc b/ash/common/system/tray/tray_popup_utils.cc index b409a3ec..e0481892 100644 --- a/ash/common/system/tray/tray_popup_utils.cc +++ b/ash/common/system/tray/tray_popup_utils.cc
@@ -173,9 +173,7 @@ TriView* TrayPopupUtils::CreateSubHeaderRowView() { TriView* tri_view = CreateMultiTargetRowView(); - tri_view->SetInsets( - gfx::Insets(0, kTrayPopupPaddingHorizontal, 0, - GetTrayConstant(TRAY_POPUP_ITEM_RIGHT_INSET))); + tri_view->SetInsets(gfx::Insets(0, kTrayPopupPaddingHorizontal, 0, 0)); tri_view->SetContainerVisible(TriView::Container::START, false); tri_view->SetContainerLayout( TriView::Container::END, @@ -187,8 +185,7 @@ TriView* tri_view = new TriView(0 /* padding_between_items */); tri_view->SetInsets( - gfx::Insets(0, GetTrayConstant(TRAY_POPUP_ITEM_LEFT_INSET), 0, - GetTrayConstant(TRAY_POPUP_ITEM_RIGHT_INSET))); + gfx::Insets(0, GetTrayConstant(TRAY_POPUP_ITEM_LEFT_INSET), 0, 0)); ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::START); ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::CENTER);
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc index 83eb415..94ff7d07 100644 --- a/base/debug/stack_trace.cc +++ b/base/debug/stack_trace.cc
@@ -111,14 +111,12 @@ // Check alignment. if (fp & (sizeof(uintptr_t) - 1)) return false; - // A PC that is too small means we've gone off the end of the stack. - const uintptr_t kMinimumReasonablePC = 32768; - if (GetStackFramePC(fp) < kMinimumReasonablePC) - return false; - if (stack_end) { // Both fp[0] and fp[1] must be within the stack. if (fp > stack_end - 2 * sizeof(uintptr_t)) return false; + + // Additional check to filter out false positives. + if (GetStackFramePC(fp) < 32768) return false; } return true;
diff --git a/base/security_unittest.cc b/base/security_unittest.cc index d5637bb..24fbbd7 100644 --- a/base/security_unittest.cc +++ b/base/security_unittest.cc
@@ -87,16 +87,14 @@ } } -#if defined(OS_IOS) || defined(OS_LINUX) || defined(ADDRESS_SANITIZER) +#if defined(OS_IOS) || defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) #define MAYBE_NewOverflow DISABLED_NewOverflow #else #define MAYBE_NewOverflow NewOverflow #endif // Test array[TooBig][X] and array[X][TooBig] allocations for int overflows. // IOS doesn't honor nothrow, so disable the test there. -// Disabled on Linux because failing Linux Valgrind bot, and Valgrind exclusions -// are not currently read. See http://crbug.com/582398 -// Disabled under ASan because asan aborts when new returns nullptr, +// Disabled under XSan because asan aborts when new returns nullptr, // https://bugs.chromium.org/p/chromium/issues/detail?id=690271#c15 TEST(SecurityTest, MAYBE_NewOverflow) { const size_t kArraySize = 4096;
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 2a05f4f..0171087 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -565,7 +565,12 @@ LayerImpl* existing_layer = LayerByElementId(element_id); bool element_id_collision_detected = existing_layer && existing_layer != layer; - DCHECK(!element_id_collision_detected); + + // TODO(pdr): Remove this suppression and always check for id collisions. + // This is a temporary suppression for SPV2 which generates unnecessary + // layers that collide. Remove once crbug.com/693693 is fixed. + if (!settings().use_layer_lists) + DCHECK(!element_id_collision_detected); #endif element_layers_map_[element_id] = layer->id();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java index 64b5858..e2799f6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -262,7 +262,7 @@ @Override public boolean onInterceptTouchEvent(MotionEvent e) { - if (isToolbarAndroidViewHidden()) return false; + if (!canMoveSheet()) return false; // The incoming motion event may have been adjusted by the view sending it down. Create a // motion event with the raw (x, y) coordinates of the original so the gesture detector @@ -755,4 +755,11 @@ @Override public void onFadingViewVisibilityChanged(boolean visible) {} + + private boolean canMoveSheet() { + boolean isInOverviewMode = mTabModelSelector != null + && (mTabModelSelector.getCurrentTab() == null + || mTabModelSelector.getCurrentTab().getActivity().isInOverviewMode()); + return !isToolbarAndroidViewHidden() && !isInOverviewMode; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS new file mode 100644 index 0000000..87d040abf --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/OWNERS
@@ -0,0 +1,2 @@ +per-file BottomSheet*=mdjones@chromium.org +per-file ToolbarProgressBar*=mdjones@chromium.org
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 69dd33d6..9fc22be 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -54,7 +54,7 @@ <!-- Privacy Page --> <message name="IDS_SETTINGS_IMPROVE_BROWSING_EXPERIENCE" desc="The text in the options panel that describes how we use web services to improve browsing experience."> - Chromium may use <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>web services<ph name="END_LINK"></a><ex></a></ex></ph> to improve your browsing experience. You may optionally disable these services at any time. + Chromium may use web services to improve your browsing experience. You may optionally disable these services. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a><ex></a></ex></ph> </message> <!-- People Page -->
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index 5cf2399..127499502 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -54,7 +54,7 @@ <!-- Privacy Page --> <message name="IDS_SETTINGS_IMPROVE_BROWSING_EXPERIENCE" desc="The text in the options panel that describes how we use web services to improve browsing experience."> - Google Chrome may use <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>web services<ph name="END_LINK"></a><ex></a></ex></ph> to improve your browsing experience. You may optionally disable these services at any time. + Google Chrome may use web services to improve your browsing experience. You may optionally disable these services. <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK"></a><ex></a></ex></ph> </message> <!-- People Page -->
diff --git a/chrome/browser/android/vr_shell/ui_elements.cc b/chrome/browser/android/vr_shell/ui_elements.cc index d90f5d7..3d6cf00 100644 --- a/chrome/browser/android/vr_shell/ui_elements.cc +++ b/chrome/browser/android/vr_shell/ui_elements.cc
@@ -196,7 +196,7 @@ } bool ContentRectangle::IsHitTestable() const { - return IsVisible() && hit_testable; + return hit_testable; } } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc index 8824338..a85fd877 100644 --- a/chrome/browser/android/vr_shell/ui_scene.cc +++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -16,6 +16,17 @@ namespace { +bool ParseFloat(const base::DictionaryValue& dict, + const std::string& key, + float* output) { + double value; + if (!dict.GetDouble(key, &value)) { + return false; + } + *output = value; + return true; +} + bool ParseRecti(const base::DictionaryValue& dict, const std::string& key, Recti* output) { @@ -323,6 +334,7 @@ void UiScene::UpdateBackgroundFromDict(const base::DictionaryValue& dict) { ParseColorf(dict, "color", &background_color_); + ParseFloat(dict, "distance", &background_distance_); } void UiScene::HandleCommands(std::unique_ptr<base::ListValue> commands, @@ -390,14 +402,14 @@ return nullptr; } -ContentRectangle* UiScene::GetContentQuad() { - return content_element_; -} - const Colorf& UiScene::GetBackgroundColor() { return background_color_; } +float UiScene::GetBackgroundDistance() { + return background_distance_; +} + const std::vector<std::unique_ptr<ContentRectangle>>& UiScene::GetUiElements() const { return ui_elements_;
diff --git a/chrome/browser/android/vr_shell/ui_scene.h b/chrome/browser/android/vr_shell/ui_scene.h index 1b1686f..3ef5eec1 100644 --- a/chrome/browser/android/vr_shell/ui_scene.h +++ b/chrome/browser/android/vr_shell/ui_scene.h
@@ -71,9 +71,8 @@ ContentRectangle* GetUiElementById(int element_id); - ContentRectangle* GetContentQuad(); - const Colorf& GetBackgroundColor(); + float GetBackgroundDistance(); private: void ApplyRecursiveTransforms(const ContentRectangle& element, @@ -85,6 +84,7 @@ std::vector<std::unique_ptr<ContentRectangle>> ui_elements_; ContentRectangle* content_element_ = nullptr; Colorf background_color_ = {0.1f, 0.1f, 0.1f, 1.0f}; + float background_distance_ = 10.0f; DISALLOW_COPY_AND_ASSIGN(UiScene); };
diff --git a/chrome/browser/android/vr_shell/ui_scene_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_unittest.cc index 02823d75..dd8ccb9f 100644 --- a/chrome/browser/android/vr_shell/ui_scene_unittest.cc +++ b/chrome/browser/android/vr_shell/ui_scene_unittest.cc
@@ -69,35 +69,6 @@ EXPECT_EQ(scene.GetUiElements().size(), 0u); } -TEST(UiScene, AddRemoveContentQuad) { - UiScene scene; - - EXPECT_EQ(scene.GetContentQuad(), nullptr); - - base::DictionaryValue dict; - dict.SetInteger("id", 0); - dict.SetInteger("fillType", Fill::CONTENT); - scene.AddUiElementFromDict(dict); - EXPECT_NE(scene.GetContentQuad(), nullptr); - - dict.SetInteger("fillType", Fill::SPRITE); - std::unique_ptr<base::DictionaryValue> copy_rect(new base::DictionaryValue); - copy_rect->SetInteger("x", 100); - copy_rect->SetInteger("y", 101); - copy_rect->SetInteger("width", 102); - copy_rect->SetInteger("height", 103); - dict.Set("copyRect", std::move(copy_rect)); - scene.UpdateUiElementFromDict(dict); - EXPECT_EQ(scene.GetContentQuad(), nullptr); - - dict.SetInteger("fillType", Fill::CONTENT); - scene.UpdateUiElementFromDict(dict); - EXPECT_NE(scene.GetContentQuad(), nullptr); - - scene.RemoveUiElement(0); - EXPECT_EQ(scene.GetContentQuad(), nullptr); -} - TEST(UiScene, AddRemoveAnimations) { UiScene scene; addElement(&scene, 0);
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc index ac346c5..73afb711 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.cc +++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -57,19 +57,10 @@ // TODO(mthiesse): Handedness options. static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; -// If there is no content quad, and the reticle isn't hitting another element, -// draw the reticle at this distance. -static constexpr float kDefaultReticleDistance = 2.0f; - // Fraction of the distance to the object the cursor is drawn at to avoid // rounding errors drawing the cursor behind the object. static constexpr float kReticleOffset = 0.99f; -// Limit the rendering distance of the reticle to the distance to a corner of -// the content quad, times this value. This lets the rendering distance -// adjust according to content quad placement. -static constexpr float kReticleDistanceMultiplier = 1.5f; - // GVR buffer indices for use with viewport->SetSourceBufferIndex // or frame.BindBuffer. We use one for world content (with reprojection) // including main VrShell and WebVR content plus world-space UI. @@ -471,37 +462,23 @@ // in the field of view. This is physically correct, but hard to use. For // usability, do the following instead: // - // - Project the controller laser onto an outer surface, which is the - // closer of the desktop plane, or a distance-limiting sphere. + // - Project the controller laser onto a distance-limiting sphere. // - Create a vector between the eyes and the outer surface point. - // - If any UI elements intersect this vector, choose the closest to the eyes, - // and place the reticle at the intersection point. + // - If any UI elements intersect this vector, and is within the bounding + // sphere, choose the closest to the eyes, and place the reticle at the + // intersection point. - // Find distance to a corner of the content quad, and limit the cursor - // distance to a multiple of that distance. This lets us keep the reticle on - // the content plane near the content window, and on the surface of a sphere - // in other directions. Note that this approach uses distance from controller, - // rather than eye, for simplicity. This will make the sphere slightly - // off-center. - float distance = kDefaultReticleDistance; - ContentRectangle* content_plane = scene_->GetContentQuad(); - if (content_plane) { - distance = content_plane->GetRayDistance(origin, forward); - gvr::Vec3f corner = {0.5f, 0.5f, 0.0f}; - corner = MatrixVectorMul(content_plane->transform.to_world, corner); - float max_distance = Distance(origin, corner) * kReticleDistanceMultiplier; - if (distance > max_distance || distance <= 0.0f) { - distance = max_distance; - } - } - + // Compute the distance from the eyes to the distance limiting sphere. Note + // that the sphere is centered at the controller, rather than the eye, for + // simplicity. + float distance = scene_->GetBackgroundDistance(); target_point_ = GetRayPoint(origin, forward, distance); gvr::Vec3f eye_to_target = target_point_; NormalizeVector(eye_to_target); // Determine which UI element (if any) intersects the line between the eyes // and the controller target position. - float closest_element_distance = std::numeric_limits<float>::infinity(); + float closest_element_distance = VectorLength(target_point_); int pixel_x = 0; int pixel_y = 0; target_element_ = nullptr;
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc index 139cdd8..8563c3c6 100644 --- a/chrome/browser/chromeos/login/login_browsertest.cc +++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -209,7 +209,8 @@ } // Verifies the cursor is not hidden at startup when user is logged in. -IN_PROC_BROWSER_TEST_F(LoginUserTest, CursorShown) { +// Test is flaky https://crbug.com/693106 +IN_PROC_BROWSER_TEST_F(LoginUserTest, DISABLED_CursorShown) { EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible()); TestSystemTrayIsVisible();
diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc index 434f1bd..1f9948c2 100644 --- a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc +++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
@@ -324,12 +324,11 @@ return false; } -bool ChromeRuntimeAPIDelegate::OpenOptionsPage(const Extension* extension) { - Profile* profile = Profile::FromBrowserContext(browser_context_); - Browser* browser = chrome::FindLastActiveWithProfile(profile); - if (!browser) - return false; - return extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser); +bool ChromeRuntimeAPIDelegate::OpenOptionsPage( + const Extension* extension, + content::BrowserContext* browser_context) { + return extensions::ExtensionTabUtil::OpenOptionsPageFromAPI(extension, + browser_context); } void ChromeRuntimeAPIDelegate::Observe(
diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h index 6ff1a05..e8649ed 100644 --- a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h +++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h
@@ -58,7 +58,8 @@ void OpenURL(const GURL& uninstall_url) override; bool GetPlatformInfo(extensions::api::runtime::PlatformInfo* info) override; bool RestartDevice(std::string* error_message) override; - bool OpenOptionsPage(const extensions::Extension* extension) override; + bool OpenOptionsPage(const extensions::Extension* extension, + content::BrowserContext* browser_context) override; // content::NotificationObserver implementation. void Observe(int type,
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index 163ebfb5..9e28e8c 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -623,15 +623,35 @@ return NULL; } +bool ExtensionTabUtil::OpenOptionsPageFromAPI( + const Extension* extension, + content::BrowserContext* browser_context) { + if (!OptionsPageInfo::HasOptionsPage(extension)) + return false; + Profile* profile = Profile::FromBrowserContext(browser_context); + // This version of OpenOptionsPage() is only called when the extension + // initiated the command via chrome.runtime.openOptionsPage. For a spanning + // mode extension, this API could only be called from a regular profile, since + // that's the only place it's running. + DCHECK(!profile->IsOffTheRecord() || IncognitoInfo::IsSplitMode(extension)); + Browser* browser = chrome::FindBrowserWithProfile(profile); + if (!browser) + browser = new Browser(Browser::CreateParams(profile)); + return extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser); +} + bool ExtensionTabUtil::OpenOptionsPage(const Extension* extension, Browser* browser) { if (!OptionsPageInfo::HasOptionsPage(extension)) return false; - // Force the options page to open in non-OTR window, because it won't be - // able to save settings from OTR. + // Force the options page to open in non-OTR window if the extension is not + // running in split mode, because it won't be able to save settings from OTR. + // This version of OpenOptionsPage() can be called from an OTR window via e.g. + // the action menu, since that's not initiated by the extension. std::unique_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer; - if (browser->profile()->IsOffTheRecord()) { + if (browser->profile()->IsOffTheRecord() && + !IncognitoInfo::IsSplitMode(extension)) { displayer.reset(new chrome::ScopedTabbedBrowserDisplayer( browser->profile()->GetOriginalProfile())); browser = displayer->browser();
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h index b01d362..06dac73a 100644 --- a/chrome/browser/extensions/extension_tab_util.h +++ b/chrome/browser/extensions/extension_tab_util.h
@@ -169,6 +169,13 @@ // Open the extension's options page. Returns true if an options page was // successfully opened (though it may not necessarily *load*, e.g. if the + // URL does not exist). This call to open the options page is iniatiated by + // the extension via chrome.runtime.openOptionsPage. + static bool OpenOptionsPageFromAPI(const Extension* extension, + content::BrowserContext* browser_context); + + // Open the extension's options page. Returns true if an options page was + // successfully opened (though it may not necessarily *load*, e.g. if the // URL does not exist). static bool OpenOptionsPage(const Extension* extension, Browser* browser);
diff --git a/chrome/browser/extensions/extension_tab_util_browsertest.cc b/chrome/browser/extensions/extension_tab_util_browsertest.cc index 4362f4e76..a458cd1 100644 --- a/chrome/browser/extensions/extension_tab_util_browsertest.cc +++ b/chrome/browser/extensions/extension_tab_util_browsertest.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/test/browser_test_utils.h" @@ -117,4 +119,184 @@ EXPECT_EQ(options_url, GetActiveUrl(browser())); } +IN_PROC_BROWSER_TEST_F(ExtensionTabUtilBrowserTest, + OpenSplitModeExtensionOptionsPageIncognito) { + const Extension* options_split_extension = LoadExtensionIncognito( + test_data_dir_.AppendASCII("options_page_split_incognito")); + ASSERT_TRUE(options_split_extension); + ASSERT_TRUE(OptionsPageInfo::HasOptionsPage(options_split_extension)); + GURL options_url = OptionsPageInfo::GetOptionsPage(options_split_extension); + + Browser* incognito = CreateIncognitoBrowser(); + + // There should be two browser windows open, regular and incognito. + EXPECT_EQ(2u, chrome::GetTotalBrowserCount()); + + // In the regular browser window, start at the new tab page, and then open the + // extension options page. + ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab")); + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + EXPECT_TRUE( + ExtensionTabUtil::OpenOptionsPage(options_split_extension, browser())); + + // Opening the options page should take the new tab and use it, so we should + // have only one tab, and it should be open to the options page. + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(browser())); + + // If the options page is already opened from a regular window, calling + // OpenOptionsPage() from an incognito window should not refocus to the + // options page in the regular window, but instead open the options page in + // the incognito window. + ui_test_utils::NavigateToURL(incognito, GURL("chrome://newtab")); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI(options_split_extension, + incognito->profile())); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + incognito->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(incognito)); + + // Both regular and incognito windows should have one tab each. + EXPECT_EQ(1, browser()->tab_strip_model()->count()); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + + // Reset the incognito browser. + CloseBrowserSynchronously(incognito); + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + incognito = CreateIncognitoBrowser(); + + // Close the regular browser. + CloseBrowserSynchronously(browser()); + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + + // In the incognito browser, start at the new tab page, and then open the + // extension options page. + ui_test_utils::NavigateToURL(incognito, GURL("chrome://newtab")); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI(options_split_extension, + incognito->profile())); + + // Opening the options page should take the new tab and use it, so we should + // have only one tab, and it should be open to the options page. + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + incognito->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(incognito)); + + // Calling OpenOptionsPage again shouldn't result in any new tabs, since we + // re-use the existing options page. + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI(options_split_extension, + incognito->profile())); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + incognito->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(incognito)); + + // Navigate to google.com (something non-newtab, non-options). Calling + // OpenOptionsPage() should create a new tab and navigate it to the options + // page. So we should have two total tabs, with the active tab pointing to + // options. + ui_test_utils::NavigateToURL(incognito, GURL("http://www.google.com/")); + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI(options_split_extension, + incognito->profile())); + EXPECT_EQ(2, incognito->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + incognito->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(incognito)); +} + +IN_PROC_BROWSER_TEST_F(ExtensionTabUtilBrowserTest, + OpenSpanningModeExtensionOptionsPageIncognito) { + const Extension* options_spanning_extension = LoadExtensionIncognito( + test_data_dir_.AppendASCII("options_page_spanning_incognito")); + ASSERT_TRUE(options_spanning_extension); + ASSERT_TRUE(OptionsPageInfo::HasOptionsPage(options_spanning_extension)); + GURL options_url = + OptionsPageInfo::GetOptionsPage(options_spanning_extension); + + // Start a regular browser window with two tabs, one that is non-options, + // non-newtab and the other that is the options page. + ui_test_utils::NavigateToURL(browser(), GURL("http://www.google.com/")); + EXPECT_TRUE( + ExtensionTabUtil::OpenOptionsPage(options_spanning_extension, browser())); + EXPECT_EQ(2, browser()->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(browser())); + // Switch to tab containing google.com such that it is the active tab. + browser()->tab_strip_model()->SelectPreviousTab(); + EXPECT_EQ(GURL("http://www.google.com/"), GetActiveUrl(browser())); + + // Spanning mode extensions can never open pages in incognito so a regular + // (non-OTR) profile must be used. If the options page is already opened from + // a regular window, calling OpenOptionsPage() from an incognito window should + // refocus to the options page in the regular window. + Browser* incognito = CreateIncognitoBrowser(); + ui_test_utils::NavigateToURL(incognito, GURL("chrome://newtab")); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI( + options_spanning_extension, profile())); + // There should be two browser windows open, regular and incognito. + EXPECT_EQ(2u, chrome::GetTotalBrowserCount()); + // Ensure that the regular browser is the foreground browser. + EXPECT_EQ(browser(), BrowserList::GetInstance()->GetLastActive()); + // The options page in the regular window should be in focus instead of + // the tab pointing to www.google.com. + EXPECT_TRUE(content::WaitForLoadStop( + browser()->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(browser())); + + // Only the incognito browser should be left. + CloseBrowserSynchronously(browser()); + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + + // Start at the new tab page in incognito and open the extension options page. + ui_test_utils::NavigateToURL(incognito, GURL("chrome://newtab")); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + EXPECT_TRUE(ExtensionTabUtil::OpenOptionsPageFromAPI( + options_spanning_extension, profile())); + + // Opening the options page from an incognito window should open a new regular + // profile window, which should have one tab open to the options page. + ASSERT_EQ(2u, chrome::GetTotalBrowserCount()); + BrowserList* browser_list = BrowserList::GetInstance(); + Browser* regular = !browser_list->get(0u)->profile()->IsOffTheRecord() + ? browser_list->get(0u) + : browser_list->get(1u); + EXPECT_EQ(1, regular->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + regular->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(regular)); + + // Leave only incognito browser open. + CloseBrowserSynchronously(regular); + EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); + + // Right-clicking on an extension action icon in the toolbar and selecting + // options should open the options page in a regular window. In this case, the + // profile is an OTR profile instead of a non-OTR profile, as described above. + ui_test_utils::NavigateToURL(incognito, GURL("chrome://newtab")); + EXPECT_EQ(1, incognito->tab_strip_model()->count()); + // Because the OpenOptionsPage() call originates from an OTR window via, e.g. + // the action menu, instead of initiated by the extension, the + // OpenOptionsPage() version that takes a Browser* is used. + EXPECT_TRUE( + ExtensionTabUtil::OpenOptionsPage(options_spanning_extension, incognito)); + // There should be two browser windows open, regular and incognito. + EXPECT_EQ(2u, chrome::GetTotalBrowserCount()); + browser_list = BrowserList::GetInstance(); + regular = !browser_list->get(0u)->profile()->IsOffTheRecord() + ? browser_list->get(0u) + : browser_list->get(1u); + // Ensure that the regular browser is the foreground browser. + EXPECT_EQ(regular, browser_list->GetLastActive()); + EXPECT_EQ(1, regular->tab_strip_model()->count()); + EXPECT_TRUE(content::WaitForLoadStop( + regular->tab_strip_model()->GetActiveWebContents())); + EXPECT_EQ(options_url, GetActiveUrl(regular)); +} + } // namespace extensions
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc index ca397ec..a13c299c 100644 --- a/chrome/browser/first_run/first_run.cc +++ b/chrome/browser/first_run/first_run.cc
@@ -326,27 +326,6 @@ std::transform(src.begin(), src.end(), ret->begin(), &UrlFromString); } -bool IsOnWelcomePage(content::WebContents* contents) { - // We have to check both the GetURL() similar to the other checks below, but - // also the original request url because the welcome page we use is a - // redirect. - // TODO(crbug.com/651465): Remove this once kUseConsolidatedStartupFlow is on - // by default. - const GURL deprecated_welcome_page( - l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL)); - if (contents->GetURL() == deprecated_welcome_page || - (contents->GetController().GetVisibleEntry() && - contents->GetController().GetVisibleEntry()->GetOriginalRequestURL() == - deprecated_welcome_page)) { - return true; - } - - const GURL welcome_page(chrome::kChromeUIWelcomeURL); - const GURL welcome_page_win10(chrome::kChromeUIWelcomeWin10URL); - const GURL current = contents->GetURL().GetWithEmptyPath(); - return current == welcome_page || current == welcome_page_win10; -} - // Show the first run search engine bubble at the first appropriate opportunity. // This bubble may be delayed by other UI, like global errors and sync promos. class FirstRunBubbleLauncher : public content::NotificationObserver { @@ -418,7 +397,7 @@ gaia::IsGaiaSignonRealm(contents->GetURL().GetOrigin()) || contents->GetURL() == chrome::GetSettingsUrl(chrome::kSyncSetupSubPage) || - IsOnWelcomePage(contents))) { + first_run::IsOnWelcomePage(contents))) { return; } @@ -715,6 +694,27 @@ return retval; } +bool IsOnWelcomePage(content::WebContents* contents) { + // We have to check both the GetURL() similar to the other checks below, but + // also the original request url because the welcome page we use is a + // redirect. + // TODO(crbug.com/651465): Remove this once kUseConsolidatedStartupFlow is on + // by default. + const GURL deprecated_welcome_page( + l10n_util::GetStringUTF8(IDS_WELCOME_PAGE_URL)); + if (contents->GetURL() == deprecated_welcome_page || + (contents->GetController().GetVisibleEntry() && + contents->GetController().GetVisibleEntry()->GetOriginalRequestURL() == + deprecated_welcome_page)) { + return true; + } + + const GURL welcome_page(chrome::kChromeUIWelcomeURL); + const GURL welcome_page_win10(chrome::kChromeUIWelcomeWin10URL); + const GURL current = contents->GetURL().GetWithEmptyPath(); + return current == welcome_page || current == welcome_page_win10; +} + void SetShouldDoPersonalDataManagerFirstRun() { g_should_do_autofill_personal_data_manager_first_run = true; }
diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h index d8abcf5..001b339 100644 --- a/chrome/browser/first_run/first_run.h +++ b/chrome/browser/first_run/first_run.h
@@ -20,6 +20,10 @@ class FilePath; } +namespace content { +class WebContents; +} + namespace user_prefs { class PrefRegistrySyncable; } @@ -136,6 +140,9 @@ // SetShouldShowWelcomePage() is called. bool ShouldShowWelcomePage(); +// Returns true if |contents| hosts one of the welcome pages. +bool IsOnWelcomePage(content::WebContents* contents); + // Iterates over the given tabs, replacing "magic words" designated for // use in Master Preferences files with corresponding URLs. std::vector<GURL> ProcessMasterPrefsTabs(const std::vector<GURL>& tabs);
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui.js b/chrome/browser/resources/vr_shell/vr_shell_ui.js index d0082161..2fd4a7a 100644 --- a/chrome/browser/resources/vr_shell/vr_shell_ui.js +++ b/chrome/browser/resources/vr_shell/vr_shell_ui.js
@@ -38,6 +38,7 @@ /** @const */ this.MENU_MODE_SCREEN_DISTANCE = 1.2; /** @const */ this.MENU_MODE_SCREEN_HEIGHT = 0.5; /** @const */ this.MENU_MODE_SCREEN_ELEVATION = 0.1; + /** @const */ this.BACKGROUND_DISTANCE_MULTIPLIER = 1.414; this.menuMode = false; this.fullscreen = false; @@ -49,6 +50,18 @@ this.SCREEN_HEIGHT * this.SCREEN_RATIO, this.SCREEN_HEIGHT); element.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); this.elementId = ui.addElement(element); + + // Place an invisible but hittable plane behind the content quad, to keep + // the reticle roughly planar with the content if near content. + let backPlane = new api.UiElement(0, 0, 0, 0); + backPlane.setVisible(false); + backPlane.setHitTestable(true); + backPlane.setSize(1000, 1000); + backPlane.setTranslation(0, 0, -0.01); + backPlane.setParentId(this.elementId); + ui.addElement(backPlane); + + this.updateState(); } setEnabled(enabled) { @@ -81,25 +94,27 @@ updateState() { // Defaults content quad parameters. let y = 0; - let z = -this.BROWSING_SCREEN_DISTANCE; + let distance = this.BROWSING_SCREEN_DISTANCE; let height = this.SCREEN_HEIGHT; // Mode-specific overrides. if (this.menuMode) { y = this.MENU_MODE_SCREEN_ELEVATION; - z = -this.MENU_MODE_SCREEN_DISTANCE; + distance = this.MENU_MODE_SCREEN_DISTANCE; height = this.MENU_MODE_SCREEN_HEIGHT; } else if (this.fullscreen) { - z = -this.FULLSCREEN_DISTANCE; + distance = this.FULLSCREEN_DISTANCE; } let anim; anim = new api.Animation(this.elementId, ANIM_DURATION); - anim.setTranslation(0, y, z); + anim.setTranslation(0, y, -distance); ui.addAnimation(anim); anim = new api.Animation(this.elementId, ANIM_DURATION); anim.setSize(height * this.SCREEN_RATIO, height); ui.addAnimation(anim); + + ui.setBackgroundDistance(distance * this.BACKGROUND_DISTANCE_MULTIPLIER); } // TODO(crbug/643815): Add a method setting aspect ratio (and possible @@ -252,8 +267,8 @@ let update = new api.UiElementUpdate(); update.setVisible(false); - update.setSize(0.5, 0.2); - update.setTranslation(0, -2, -1); + update.setSize(0.25, 0.1); + update.setTranslation(0, -1.5, -1.5); update.setRotation(1, 0, 0, -0.8); ui.updateElement(this.uiElement.uiElementId, update); } @@ -566,6 +581,8 @@ groundGrid.setRotation(1.0, 0.0, 0.0, -Math.PI / 2); groundGrid.setDrawPhase(0); this.groundGridId = ui.addElement(groundGrid); + + ui.setBackgroundColor(this.HORIZON_COLOR); } setEnabled(enabled) {
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js index cefeffd..751372d 100644 --- a/chrome/browser/resources/vr_shell/vr_shell_ui_api.js +++ b/chrome/browser/resources/vr_shell/vr_shell_ui_api.js
@@ -322,6 +322,9 @@ constructor(pixelX, pixelY, pixelWidth, pixelHeight) { super(); + // Apply defaults to new elements. + this.setVisible(true); + this.setHitTestable(true); this.setFill(new api.Sprite(pixelX, pixelY, pixelWidth, pixelHeight)); } };
diff --git a/chrome/browser/resources/vr_shell/vr_shell_ui_scene.js b/chrome/browser/resources/vr_shell/vr_shell_ui_scene.js index d1651a5..4ed691a 100644 --- a/chrome/browser/resources/vr_shell/vr_shell_ui_scene.js +++ b/chrome/browser/resources/vr_shell/vr_shell_ui_scene.js
@@ -129,12 +129,27 @@ delete this.animations[id]; } + /** + * Set the background color of the scene. + * @param {{r: number, b: number, g: number, a: number}} color + */ setBackgroundColor(color) { this.commands.push( {'type': api.Command.UPDATE_BACKGROUND, 'data': {'color': color}}); } /** + * Set the radius of background-bounding sphere. + * @param {number} distance + */ + setBackgroundDistance(distance) { + this.commands.push({ + 'type': api.Command.UPDATE_BACKGROUND, + 'data': {'distance': distance} + }); + } + + /** * Purge all elements in the scene. */ purge() {
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc index 06bfc0f..cc84db9a 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -38,9 +38,7 @@ void AutomationManagerAura::Enable(BrowserContext* context) { enabled_ = true; - if (!current_tree_.get()) - current_tree_.reset(new AXTreeSourceAura()); - ResetSerializer(); + Reset(false); SendEvent(context, current_tree_->GetRoot(), ui::AX_EVENT_LOAD_COMPLETE); views::AXAuraObjCache::GetInstance()->SetDelegate(this); @@ -57,9 +55,7 @@ void AutomationManagerAura::Disable() { enabled_ = false; - - // Reset the serializer to save memory. - current_tree_serializer_->Reset(); + Reset(true); } void AutomationManagerAura::HandleEvent(BrowserContext* context, @@ -151,9 +147,12 @@ AutomationManagerAura::~AutomationManagerAura() { } -void AutomationManagerAura::ResetSerializer() { - current_tree_serializer_.reset( - new AuraAXTreeSerializer(current_tree_.get())); +void AutomationManagerAura::Reset(bool reset_serializer) { + if (!current_tree_) + current_tree_.reset(new AXTreeSourceAura()); + reset_serializer ? current_tree_serializer_.reset() + : current_tree_serializer_.reset( + new AuraAXTreeSerializer(current_tree_.get())); } void AutomationManagerAura::SendEvent(BrowserContext* context,
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h index 9da79fc..811e5aa 100644 --- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h +++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -67,8 +67,9 @@ private: friend struct base::DefaultSingletonTraits<AutomationManagerAura>; - // Reset all state in this manager. - void ResetSerializer(); + // Reset state in this manager. If |reset_serializer| is true, reset the + // serializer to save memory. + void Reset(bool reset_serializer); void SendEvent(content::BrowserContext* context, views::AXAuraObjWrapper* aura_obj,
diff --git a/chrome/browser/ui/startup/default_browser_prompt.cc b/chrome/browser/ui/startup/default_browser_prompt.cc index fb88173..6402a3f 100644 --- a/chrome/browser/ui/startup/default_browser_prompt.cc +++ b/chrome/browser/ui/startup/default_browser_prompt.cc
@@ -16,6 +16,7 @@ #include "base/version.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/first_run/first_run.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" @@ -52,6 +53,14 @@ if (!web_contents) return; + // Never show the default browser prompt over the first run promos. + // TODO(pmonette): The whole logic that determines when to show the default + // browser prompt is due for a refactor. ShouldShowDefaultBrowserPrompt() + // should be aware of the first run promos and return false instead of + // counting on the early return here. See bug crbug.com/693292. + if (first_run::IsOnWelcomePage(web_contents)) + return; + DefaultBrowserInfoBarDelegate::Create( InfoBarService::FromWebContents(web_contents), browser->profile()); }
diff --git a/chrome/browser/ui/webui/profiler_ui.cc b/chrome/browser/ui/webui/profiler_ui.cc index a9e9fee..2bf297e4 100644 --- a/chrome/browser/ui/webui/profiler_ui.cc +++ b/chrome/browser/ui/webui/profiler_ui.cc
@@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/debug/debugging_flags.h" +#include "base/debug/thread_heap_usage_tracker.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" @@ -107,8 +108,9 @@ source->AddResourcePath("profiler.js", IDR_PROFILER_JS); source->SetDefaultResource(IDR_PROFILER_HTML); source->UseGzip(std::unordered_set<std::string>()); - source->AddBoolean("enableMemoryTaskProfiler", - BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)); + source->AddBoolean( + "enableMemoryTaskProfiler", + base::debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled()); return source; }
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc index d490a6f7..122dd54 100644 --- a/chrome/common/chrome_paths.cc +++ b/chrome/common/chrome_paths.cc
@@ -146,18 +146,11 @@ #else // Debug builds write next to the binary (in the build tree) #if defined(OS_MACOSX) - if (!PathService::Get(base::DIR_EXE, result)) - return false; + // Apps may not write into their own bundle. if (base::mac::AmIBundled()) { - // If we're called from chrome, dump it beside the app (outside the - // app bundle), if we're called from a unittest, we'll already - // outside the bundle so use the exe dir. - // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. - *result = result->DirName(); - *result = result->DirName(); - *result = result->DirName(); + return PathService::Get(chrome::DIR_USER_DATA, result); } - return true; + return PathService::Get(base::DIR_EXE, result); #else return PathService::Get(base::DIR_EXE, result); #endif // defined(OS_MACOSX)
diff --git a/chrome/test/data/extensions/options_page_spanning_incognito/manifest.json b/chrome/test/data/extensions/options_page_spanning_incognito/manifest.json new file mode 100644 index 0000000..b955557 --- /dev/null +++ b/chrome/test/data/extensions/options_page_spanning_incognito/manifest.json
@@ -0,0 +1,8 @@ +{ + "name": "Extension With Options Page", + "description": "A spanning mode extension with an options page", + "options_page": "options.html", + "incognito": "spanning", + "version": "0.1.1", + "manifest_version": 2 +}
diff --git a/chrome/test/data/extensions/options_page_spanning_incognito/options.html b/chrome/test/data/extensions/options_page_spanning_incognito/options.html new file mode 100644 index 0000000..67fc120 --- /dev/null +++ b/chrome/test/data/extensions/options_page_spanning_incognito/options.html
@@ -0,0 +1,8 @@ +<html> + <style> + html { + border: 1px solid green; + } + </style> + An options page +</html>
diff --git a/chrome/test/data/extensions/options_page_split_incognito/manifest.json b/chrome/test/data/extensions/options_page_split_incognito/manifest.json new file mode 100644 index 0000000..15ac1f9 --- /dev/null +++ b/chrome/test/data/extensions/options_page_split_incognito/manifest.json
@@ -0,0 +1,8 @@ +{ + "name": "Extension With Options Page", + "description": "A split mode extension with an options page", + "options_page": "options.html", + "incognito": "split", + "version": "0.1.1", + "manifest_version": 2 +}
diff --git a/chrome/test/data/extensions/options_page_split_incognito/options.html b/chrome/test/data/extensions/options_page_split_incognito/options.html new file mode 100644 index 0000000..67fc120 --- /dev/null +++ b/chrome/test/data/extensions/options_page_split_incognito/options.html
@@ -0,0 +1,8 @@ +<html> + <style> + html { + border: 1px solid green; + } + </style> + An options page +</html>
diff --git a/extensions/browser/api/runtime/runtime_api.cc b/extensions/browser/api/runtime/runtime_api.cc index 7e08c04..f5644c4b 100644 --- a/extensions/browser/api/runtime/runtime_api.cc +++ b/extensions/browser/api/runtime/runtime_api.cc
@@ -417,8 +417,9 @@ return ScheduleDelayedRestart(now, seconds_from_now); } -bool RuntimeAPI::OpenOptionsPage(const Extension* extension) { - return delegate_->OpenOptionsPage(extension); +bool RuntimeAPI::OpenOptionsPage(const Extension* extension, + content::BrowserContext* browser_context) { + return delegate_->OpenOptionsPage(extension, browser_context); } void RuntimeAPI::MaybeCancelRunningDelayedRestartTimer() { @@ -660,7 +661,7 @@ ExtensionFunction::ResponseAction RuntimeOpenOptionsPageFunction::Run() { RuntimeAPI* api = RuntimeAPI::GetFactoryInstance()->Get(browser_context()); - return RespondNow(api->OpenOptionsPage(extension()) + return RespondNow(api->OpenOptionsPage(extension(), browser_context()) ? NoArguments() : Error(kFailedToCreateOptionsPage)); }
diff --git a/extensions/browser/api/runtime/runtime_api.h b/extensions/browser/api/runtime/runtime_api.h index e3329a4..3797908f 100644 --- a/extensions/browser/api/runtime/runtime_api.h +++ b/extensions/browser/api/runtime/runtime_api.h
@@ -86,7 +86,8 @@ const std::string& extension_id, int seconds_from_now); - bool OpenOptionsPage(const Extension* extension); + bool OpenOptionsPage(const Extension* extension, + content::BrowserContext* browser_context); private: friend class BrowserContextKeyedAPIFactory<RuntimeAPI>;
diff --git a/extensions/browser/api/runtime/runtime_api_delegate.cc b/extensions/browser/api/runtime/runtime_api_delegate.cc index b012c74..ce23440 100644 --- a/extensions/browser/api/runtime/runtime_api_delegate.cc +++ b/extensions/browser/api/runtime/runtime_api_delegate.cc
@@ -13,7 +13,9 @@ : success(success), response(response), version(version) { } -bool RuntimeAPIDelegate::OpenOptionsPage(const Extension* extension) { +bool RuntimeAPIDelegate::OpenOptionsPage( + const Extension* extension, + content::BrowserContext* browser_context) { return false; }
diff --git a/extensions/browser/api/runtime/runtime_api_delegate.h b/extensions/browser/api/runtime/runtime_api_delegate.h index bd73f7a..f0ac21c4 100644 --- a/extensions/browser/api/runtime/runtime_api_delegate.h +++ b/extensions/browser/api/runtime/runtime_api_delegate.h
@@ -10,6 +10,10 @@ class GURL; +namespace content { +class BrowserContext; +} + namespace extensions { namespace api { @@ -74,7 +78,8 @@ // Open |extension|'s options page, if it has one. Returns true if an // options page was opened, false otherwise. See the docs of the // chrome.runtime.openOptionsPage function for the gritty details. - virtual bool OpenOptionsPage(const Extension* extension); + virtual bool OpenOptionsPage(const Extension* extension, + content::BrowserContext* browser_context); }; } // namespace extensions
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index 9b17b92..56695088 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -9,6 +9,7 @@ import("//ios/public/provider/chrome/browser/build_config.gni") source_set("app") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "deferred_initialization_runner.h", "deferred_initialization_runner.mm",
diff --git a/ios/chrome/app/deferred_initialization_runner.mm b/ios/chrome/app/deferred_initialization_runner.mm index 7e175b4..01fa251 100644 --- a/ios/chrome/app/deferred_initialization_runner.mm +++ b/ios/chrome/app/deferred_initialization_runner.mm
@@ -6,19 +6,16 @@ #include <stdint.h> -#import "base/ios/weak_nsobject.h" #include "base/logging.h" #include "base/mac/scoped_block.h" -#include "base/mac/scoped_nsobject.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif // An object encapsulating the deferred execution of a block of initialization // code. -@interface DeferredInitializationBlock : NSObject { - // A string to reference the initialization block. - base::scoped_nsobject<NSString> _name; - // A block of code to execute. - base::mac::ScopedBlock<ProceduralBlock> _runBlock; -} +@interface DeferredInitializationBlock : NSObject - (instancetype)init NS_UNAVAILABLE; @@ -34,7 +31,12 @@ @end -@implementation DeferredInitializationBlock +@implementation DeferredInitializationBlock { + // A string to reference the initialization block. + NSString* _name; + // A block of code to execute. + ProceduralBlock _runBlock; +} // Overrides default designated initializer. - (instancetype)init { @@ -46,15 +48,15 @@ DCHECK(block); self = [super init]; if (self) { - _name.reset([name copy]); - _runBlock.reset(block, base::scoped_policy::RETAIN); + _name = [name copy]; + _runBlock = block; } return self; } - (void)run { DCHECK([NSThread isMainThread]); - ProceduralBlock deferredBlock = _runBlock.get(); + ProceduralBlock deferredBlock = _runBlock; if (!deferredBlock) return; deferredBlock(); @@ -62,14 +64,14 @@ } - (void)cancel { - _runBlock.reset(); + _runBlock = nil; } @end @interface DeferredInitializationRunner () { - base::scoped_nsobject<NSMutableArray> _blocksNameQueue; - base::scoped_nsobject<NSMutableDictionary> _runBlocks; + NSMutableArray* _blocksNameQueue; + NSMutableDictionary* _runBlocks; BOOL _isBlockScheduled; } @@ -102,8 +104,8 @@ - (instancetype)init { self = [super init]; if (self) { - _blocksNameQueue.reset([[NSMutableArray array] retain]); - _runBlocks.reset([[NSMutableDictionary dictionary] retain]); + _blocksNameQueue = [NSMutableArray array]; + _runBlocks = [NSMutableDictionary dictionary]; _isBlockScheduled = NO; _delayBetweenBlocks = 0.2; _delayBeforeFirstBlock = 3.0; @@ -117,8 +119,8 @@ [self cancelBlockNamed:name]; [_blocksNameQueue addObject:name]; - base::scoped_nsobject<DeferredInitializationBlock> deferredBlock( - [[DeferredInitializationBlock alloc] initWithName:name block:block]); + DeferredInitializationBlock* deferredBlock = + [[DeferredInitializationBlock alloc] initWithName:name block:block]; [_runBlocks setObject:deferredBlock forKey:name]; if (!_isBlockScheduled) { @@ -137,7 +139,7 @@ [_runBlocks objectForKey:nextBlockName]; DCHECK(nextBlock); - base::WeakNSObject<DeferredInitializationRunner> weakSelf(self); + __weak DeferredInitializationRunner* weakSelf = self; dispatch_after( dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)),
diff --git a/ios/chrome/app/safe_mode_crashing_modules_config.mm b/ios/chrome/app/safe_mode_crashing_modules_config.mm index e9ec67c..2cde7ad 100644 --- a/ios/chrome/app/safe_mode_crashing_modules_config.mm +++ b/ios/chrome/app/safe_mode_crashing_modules_config.mm
@@ -6,7 +6,10 @@ #include "base/logging.h" #include "base/mac/foundation_util.h" -#import "base/mac/scoped_nsobject.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif namespace { @@ -15,12 +18,9 @@ } // namespace -@interface SafeModeCrashingModulesConfig () { - base::scoped_nsobject<NSDictionary> _configuration; +@implementation SafeModeCrashingModulesConfig { + NSDictionary* _configuration; } -@end - -@implementation SafeModeCrashingModulesConfig + (SafeModeCrashingModulesConfig*)sharedInstance { static SafeModeCrashingModulesConfig* instance = @@ -34,8 +34,7 @@ NSString* configPath = [[NSBundle mainBundle] pathForResource:@"SafeModeCrashingModules" ofType:@"plist"]; - _configuration.reset( - [[NSDictionary alloc] initWithContentsOfFile:configPath]); + _configuration = [[NSDictionary alloc] initWithContentsOfFile:configPath]; } return self; }
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm index 0e52721..a6eda18 100644 --- a/ios/chrome/browser/tabs/tab.mm +++ b/ios/chrome/browser/tabs/tab.mm
@@ -372,6 +372,14 @@ // Called when the UIApplication's state becomes active. - (void)applicationDidBecomeActive; + +// Returns YES if popups requested by a page with |URL| should be blocked. +- (BOOL)shouldBlockPopupForPageWithURL:(const GURL&)URL; + +// Blocks popup for page with |popupURL|, requested by the page with +// |openerURL|. +- (void)blockPopupForURL:(const GURL&)popupURL openerURL:(const GURL&)openerURL; + @end namespace { @@ -1470,6 +1478,40 @@ } } +- (BOOL)shouldBlockPopupForPageWithURL:(const GURL&)URL { + HostContentSettingsMap* settingMap = + ios::HostContentSettingsMapFactory::GetForBrowserState(browserState_); + ContentSetting setting = settingMap->GetContentSetting( + URL, URL, CONTENT_SETTINGS_TYPE_POPUPS, std::string()); + return setting != CONTENT_SETTING_ALLOW; +} + +- (void)blockPopupForURL:(const GURL&)popupURL + openerURL:(const GURL&)openerURL { + web::NavigationItem* item = [self navigationManager]->GetLastCommittedItem(); + web::Referrer referrer(openerURL, item->GetReferrer().policy); + GURL localPopupURL(popupURL); + base::WeakNSObject<Tab> weakSelf(self); + // TODO(crbug.com/692117): Remove |window_name| from constructor. + web::BlockedPopupInfo poupInfo(popupURL, referrer, nil /* window_name */, ^{ + base::scoped_nsobject<Tab> strongSelf([weakSelf retain]); + if (!strongSelf) { + return; + } + [strongSelf updateSnapshotWithOverlay:YES visibleFrameOnly:YES]; + [strongSelf.get()->parentTabModel_ + insertOrUpdateTabWithURL:localPopupURL + referrer:referrer + transition:ui::PAGE_TRANSITION_LINK + windowName:nil + opener:self + openedByDOM:YES + atIndex:TabModelConstants::kTabPositionAutomatically + inBackground:NO]; + }); + BlockedPopupTabHelper::FromWebState(self.webState)->HandlePopup(poupInfo); +} + #pragma mark - #pragma mark FindInPageControllerDelegate @@ -1584,40 +1626,6 @@ #pragma mark - CRWWebDelegate and CRWWebStateObserver protocol methods. -- (CRWWebController*)webPageOrderedOpen:(const GURL&)URL - referrer:(const web::Referrer&)referrer - windowName:(NSString*)windowName - inBackground:(BOOL)inBackground { - DCHECK(parentTabModel_); - if (!inBackground) - [self updateSnapshotWithOverlay:YES visibleFrameOnly:YES]; - // Open a new tab or update an existing one. Tabs opened from a web page are - Tab* tab = [parentTabModel_ - insertOrUpdateTabWithURL:URL - referrer:referrer - transition:ui::PAGE_TRANSITION_LINK - windowName:windowName - opener:self - openedByDOM:YES - atIndex:TabModelConstants::kTabPositionAutomatically - inBackground:inBackground]; - return tab.webController; -} - -// This can be combined with the other versions once Tab loading is separated -// from creation. -- (CRWWebController*)webPageOrderedOpen { - [self updateSnapshotWithOverlay:YES visibleFrameOnly:YES]; - - Tab* tab = [parentTabModel_ - insertBlankTabWithTransition:ui::PAGE_TRANSITION_LINK - opener:self - openedByDOM:YES - atIndex:TabModelConstants::kTabPositionAutomatically - inBackground:NO]; - return tab.webController; -} - // The web page wants to close its own window. - (void)webPageOrderedClose { // Only allow a web page to close itself if it was opened by DOM, or if there @@ -1990,21 +1998,26 @@ [delegate_ discardPrerender]; } -- (BOOL)webController:(CRWWebController*)webController - shouldBlockPopupWithURL:(const GURL&)popupURL - sourceURL:(const GURL&)sourceURL { - ContentSetting setting = - ios::HostContentSettingsMapFactory::GetForBrowserState(browserState_) - ->GetContentSetting(sourceURL, sourceURL, - CONTENT_SETTINGS_TYPE_POPUPS, std::string()); +- (CRWWebController*)webController:(CRWWebController*)webController + createWebControllerForURL:(const GURL&)URL + openerURL:(const GURL&)openerURL + initiatedByUser:(BOOL)initiatedByUser { + BOOL shouldBlockPopUp = + !initiatedByUser && [self shouldBlockPopupForPageWithURL:openerURL]; - return setting != CONTENT_SETTING_ALLOW; -} + if (shouldBlockPopUp) { + [self blockPopupForURL:URL openerURL:openerURL]; + return nil; + } -- (void)webController:(CRWWebController*)webController - didBlockPopup:(const web::BlockedPopupInfo&)blockedPopupInfo { - BlockedPopupTabHelper::FromWebState(self.webState) - ->HandlePopup(blockedPopupInfo); + [self updateSnapshotWithOverlay:YES visibleFrameOnly:YES]; + Tab* tab = [parentTabModel_ + insertBlankTabWithTransition:ui::PAGE_TRANSITION_LINK + opener:self + openedByDOM:YES + atIndex:TabModelConstants::kTabPositionAutomatically + inBackground:NO]; + return tab.webController; } - (CGFloat)headerHeightForWebController:(CRWWebController*)webController {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index dedf5a9..102e29ed 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -4317,6 +4317,7 @@ CRWWebController* webController = tab.webController; NSString* script = @"document.documentElement.outerHTML;"; base::WeakNSObject<Tab> weakTab(tab); + base::WeakNSObject<BrowserViewController> weakSelf(self); web::JavaScriptResultBlock completionHandlerBlock = ^(id result, NSError*) { base::scoped_nsobject<Tab> strongTab([weakTab retain]); if (!strongTab) @@ -4327,10 +4328,16 @@ base::Base64Encode(base::SysNSStringToUTF8(result), &base64HTML); GURL URL(std::string("data:text/plain;charset=utf-8;base64,") + base64HTML); web::Referrer referrer([strongTab url], web::ReferrerPolicyDefault); - [strongTab webPageOrderedOpen:URL - referrer:referrer - windowName:nil - inBackground:NO]; + + [[weakSelf tabModel] + insertOrUpdateTabWithURL:URL + referrer:referrer + transition:ui::PAGE_TRANSITION_LINK + windowName:nil + opener:strongTab + openedByDOM:YES + atIndex:TabModelConstants::kTabPositionAutomatically + inBackground:NO]; }; [webController executeJavaScript:script completionHandler:completionHandlerBlock];
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h index d64f8044..4069c877 100644 --- a/ios/web/public/web_state/ui/crw_web_delegate.h +++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -21,32 +21,12 @@ @class CRWSessionEntry; @class CRWWebController; -namespace web { -class BlockedPopupInfo; -struct Referrer; -} - // Methods implemented by the delegate of the CRWWebController. // DEPRECATED, do not conform to this protocol and do not add any methods to it. // Use web::WebStateDelegate instead. // TODO(crbug.com/674991): Remove this protocol. @protocol CRWWebDelegate<NSObject> -// Called when the page wants to open a new window by DOM (e.g. with -// |window.open| JavaScript call or by clicking a link with |_blank| target) or -// wants to open a window with a new tab. |inBackground| allows a page to force -// a new window to open in the background. CRWSessionController's openedByDOM -// property of the returned CRWWebController must be YES. -- (CRWWebController*)webPageOrderedOpen:(const GURL&)url - referrer:(const web::Referrer&)referrer - windowName:(NSString*)windowName - inBackground:(BOOL)inBackground; - -// Called when the page wants to open a new window by DOM. -// CRWSessionController's openedByDOM property of the returned CRWWebController -// must be YES. -- (CRWWebController*)webPageOrderedOpen; - // Called when the page calls window.close() on itself. Begin the shut-down // sequence for this controller. - (void)webPageOrderedClose; @@ -103,6 +83,16 @@ - (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry; // --------------------------------------------------------------------- +// Called when |webController| wants to open a new window. |URL| is the URL of +// the new window; |openerURL| is the URL of the page which requested a window +// to be open; |initiatedByUser| is YES if action was caused by the user. +// |webController| will not open a window if this method returns nil. This +// method can not return |webController|. +- (CRWWebController*)webController:(CRWWebController*)webController + createWebControllerForURL:(const GURL&)URL + openerURL:(const GURL&)openerURL + initiatedByUser:(BOOL)initiatedByUser; + @optional // Called to ask CRWWebDelegate if |CRWWebController| should open the given URL. @@ -140,20 +130,6 @@ - (void)webController:(CRWWebController*)webController titleDidChange:(NSString*)title; -// Called when CRWWebController has detected a popup. If NO is returned then -// popup will be shown, otherwise |webController:didBlockPopup:| will be called -// and CRWWebDelegate will have a chance to unblock the popup later. NO is -// assumed by default if this method is not implemented. -- (BOOL)webController:(CRWWebController*)webController - shouldBlockPopupWithURL:(const GURL&)popupURL - sourceURL:(const GURL&)sourceURL; - -// Called when CRWWebController has detected and blocked a popup. In order to -// allow the blocked pop up CRWWebDelegate must call -// |blockedPopupInfo.ShowPopup()| instead of attempting to open a new window. -- (void)webController:(CRWWebController*)webController - didBlockPopup:(const web::BlockedPopupInfo&)blockedPopupInfo; - // Called when CRWWebController did suppress a dialog (JavaScript, HTTP // authentication or window.open). // NOTE: Called only if CRWWebController.shouldSuppressDialogs is set to YES.
diff --git a/ios/web/web_state/js/resources/core.js b/ios/web/web_state/js/resources/core.js index d38360928..f1a302f2 100644 --- a/ios/web/web_state/js/resources/core.js +++ b/ios/web/web_state/js/resources/core.js
@@ -363,12 +363,6 @@ return 'default'; }; - // Provides a way for other injected javascript to access the page's referrer - // policy. - __gCrWeb['getPageReferrerPolicy'] = function() { - return getReferrerPolicy_(); - }; - // Various aspects of global DOM behavior are overridden here. // A popstate event needs to be fired anytime the active history entry
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index d7b23f9..9be54a3 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -78,7 +78,6 @@ #include "ios/web/public/web_state/url_verification_constants.h" #import "ios/web/public/web_state/web_state.h" #include "ios/web/public/webui/web_ui_ios.h" -#import "ios/web/web_state/blocked_popup_info.h" #import "ios/web/web_state/crw_pass_kit_downloader.h" #import "ios/web/web_state/crw_web_view_proxy_impl.h" #import "ios/web/web_state/error_translation_util.h" @@ -103,6 +102,7 @@ #import "ios/web/webui/mojo_facade.h" #import "net/base/mac/url_conversions.h" #include "net/base/net_errors.h" +#include "net/ssl/ssl_info.h" #include "services/service_manager/public/cpp/interface_registry.h" #include "ui/base/page_transition_types.h" #include "url/gurl.h" @@ -533,8 +533,8 @@ // Returns the WKWebViewConfigurationProvider associated with the web // controller's BrowserState. - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider; -// Extracts Referer value from WKNavigationAction request header. -- (NSString*)refererFromNavigationAction:(WKNavigationAction*)action; +// Extracts "Referer" [sic] value from WKNavigationAction request header. +- (NSString*)referrerFromNavigationAction:(WKNavigationAction*)action; // Returns the current URL of the web view, and sets |trustLevel| accordingly // based on the confidence in the verification. @@ -689,8 +689,6 @@ (const web::PageScrollState&)scrollState; // Returns the referrer for the current page. - (web::Referrer)currentReferrer; -// Asynchronously returns the referrer policy for the current page. -- (void)queryPageReferrerPolicy:(void (^)(NSString*))responseHandler; // Adds a new CRWSessionEntry with the given URL and state object to the history // stack. A state object is a serialized generic JavaScript object that contains // details of the UI's state for a given CRWSessionEntry/URL. @@ -717,9 +715,6 @@ // Inject windowID if not yet injected. - (void)injectWindowID; -// Creates a new opened by DOM window and returns its autoreleased web -// controller. -- (CRWWebController*)createChildWebController; // Returns YES if the given WKBackForwardListItem is valid to use for // navigation. @@ -747,13 +742,6 @@ // Called when a JavaScript dialog, HTTP authentication dialog or window.open // call has been suppressed. - (void)didSuppressDialog; -// Convenience method to inform CWRWebDelegate about a blocked popup. -- (void)didBlockPopupWithURL:(GURL)popupURL sourceURL:(GURL)sourceURL; -// Informs CWRWebDelegate that CRWWebController has detected and blocked a -// popup. -- (void)didBlockPopupWithURL:(GURL)popupURL - sourceURL:(GURL)sourceURL - referrerPolicy:(const std::string&)referrerPolicyString; // Returns YES if the navigation action is associated with a main frame request. - (BOOL)isMainFrameNavigationAction:(WKNavigationAction*)action; // Returns whether external URL navigation action should be opened. @@ -768,10 +756,6 @@ // Called when a load ends in an SSL error and certificate chain. - (void)handleSSLCertError:(NSError*)error; -// Returns YES if the popup should be blocked, NO otherwise. -- (BOOL)shouldBlockPopupWithURL:(const GURL&)popupURL - sourceURL:(const GURL&)sourceURL; - // Used in webView:didReceiveAuthenticationChallenge:completionHandler: to // reply with NSURLSessionAuthChallengeDisposition and credentials. - (void)processAuthChallenge:(NSURLAuthenticationChallenge*)challenge @@ -1343,15 +1327,6 @@ web::ReferrerPolicyAlways); } -- (void)queryPageReferrerPolicy:(void (^)(NSString*))responseHandler { - DCHECK(responseHandler); - [self executeJavaScript:@"__gCrWeb.getPageReferrerPolicy()" - completionHandler:^(id referrer, NSError* error) { - DCHECK_NE(error.code, WKErrorJavaScriptExceptionOccurred); - responseHandler(base::mac::ObjCCast<NSString>(referrer)); - }]; -} - - (void)pushStateWithPageURL:(const GURL&)pageURL stateObject:(NSString*)stateObject transition:(ui::PageTransition)transition { @@ -1484,12 +1459,6 @@ [_windowIDJSManager inject]; } -- (CRWWebController*)createChildWebController { - CRWWebController* result = [self.delegate webPageOrderedOpen]; - DCHECK(!result || result.sessionController.openedByDOM); - return result; -} - - (BOOL)canUseViewForGeneratingOverlayPlaceholderView { return _containerView != nil; } @@ -1718,7 +1687,7 @@ _pendingNavigationInfo.reset( [[CRWWebControllerPendingNavigationInfo alloc] init]); [_pendingNavigationInfo - setReferrer:[self refererFromNavigationAction:action]]; + setReferrer:[self referrerFromNavigationAction:action]]; [_pendingNavigationInfo setNavigationType:action.navigationType]; [_pendingNavigationInfo setHTTPMethod:action.request.HTTPMethod]; } @@ -3410,21 +3379,6 @@ } #pragma mark - -#pragma mark Popup handling - -- (BOOL)shouldBlockPopupWithURL:(const GURL&)popupURL - sourceURL:(const GURL&)sourceURL { - if (![_delegate respondsToSelector:@selector(webController: - shouldBlockPopupWithURL: - sourceURL:)]) { - return NO; - } - return [_delegate webController:self - shouldBlockPopupWithURL:popupURL - sourceURL:sourceURL]; -} - -#pragma mark - #pragma mark Auth Challenge - (void)processAuthChallenge:(NSURLAuthenticationChallenge*)challenge @@ -4012,42 +3966,6 @@ [_delegate webControllerDidSuppressDialog:self]; } -- (void)didBlockPopupWithURL:(GURL)popupURL - sourceURL:(GURL)sourceURL - referrerPolicy:(const std::string&)referrerPolicyString { - web::ReferrerPolicy referrerPolicy = - web::ReferrerPolicyFromString(referrerPolicyString); - web::Referrer referrer(sourceURL, referrerPolicy); - NSString* const kWindowName = @""; // obsoleted - base::WeakNSObject<CRWWebController> weakSelf(self); - void (^showPopupHandler)() = ^{ - // On Desktop cross-window comunication is not supported for unblocked - // popups; so it's ok to create a new independent page. - CRWWebController* child = - [[weakSelf delegate] webPageOrderedOpen:popupURL - referrer:referrer - windowName:kWindowName - inBackground:NO]; - DCHECK(!child || child.sessionController.openedByDOM); - }; - - web::BlockedPopupInfo info(popupURL, referrer, kWindowName, showPopupHandler); - [self.delegate webController:self didBlockPopup:info]; -} - -- (void)didBlockPopupWithURL:(GURL)popupURL sourceURL:(GURL)sourceURL { - if ([_delegate respondsToSelector:@selector(webController:didBlockPopup:)]) { - base::WeakNSObject<CRWWebController> weakSelf(self); - dispatch_async(dispatch_get_main_queue(), ^{ - [self queryPageReferrerPolicy:^(NSString* policy) { - [weakSelf didBlockPopupWithURL:popupURL - sourceURL:sourceURL - referrerPolicy:base::SysNSStringToUTF8(policy)]; - }]; - }); - } -} - - (BOOL)isMainFrameNavigationAction:(WKNavigationAction*)action { if (action.targetFrame) { return action.targetFrame.mainFrame; @@ -4442,28 +4360,23 @@ return nil; } + // Do not create windows for non-empty invalid URLs. GURL requestURL = net::GURLWithNSURL(action.request.URL); - - // Don't create windows for non-empty invalid URLs. if (!requestURL.is_empty() && !requestURL.is_valid()) { DLOG(WARNING) << "Unable to open a window with invalid URL: " << requestURL.spec(); return nil; } - if (![self userIsInteracting]) { - NSString* referer = [self refererFromNavigationAction:action]; - GURL referrerURL = - referer ? GURL(base::SysNSStringToUTF8(referer)) : [self currentURL]; - if ([self shouldBlockPopupWithURL:requestURL sourceURL:referrerURL]) { - [self didBlockPopupWithURL:requestURL sourceURL:referrerURL]; - // Desktop Chrome does not return a window for the blocked popups; - // follow the same approach by returning nil; - return nil; - } - } + NSString* referrer = [self referrerFromNavigationAction:action]; + GURL openerURL = + referrer ? GURL(base::SysNSStringToUTF8(referrer)) : _documentURL; + CRWWebController* child = [_delegate webController:self + createWebControllerForURL:requestURL + openerURL:openerURL + initiatedByUser:[self userIsInteracting]]; + DCHECK(!child || child.sessionController.openedByDOM); - CRWWebController* child = [self createChildWebController]; // WKWebView requires WKUIDelegate to return a child view created with // exactly the same |configuration| object (exception is raised if config is // different). |configuration| param and config returned by @@ -5320,8 +5233,8 @@ _loadPhase = web::LOAD_REQUESTED; } -- (NSString*)refererFromNavigationAction:(WKNavigationAction*)action { - return [action.request valueForHTTPHeaderField:@"Referer"]; +- (NSString*)referrerFromNavigationAction:(WKNavigationAction*)action { + return [action.request valueForHTTPHeaderField:kReferrerHeaderName]; } @end
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 16fad14..5f076056 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -31,7 +31,6 @@ #include "ios/web/public/web_state/web_state_observer.h" #import "ios/web/test/web_test_with_web_controller.h" #import "ios/web/test/wk_web_view_crash_utils.h" -#import "ios/web/web_state/blocked_popup_info.h" #import "ios/web/web_state/ui/crw_web_controller_container_view.h" #import "ios/web/web_state/web_state_impl.h" #import "ios/web/web_state/wk_web_view_security_util.h" @@ -56,35 +55,27 @@ // Used to mock CRWWebDelegate methods with C++ params. @interface MockInteractionLoader : OCMockComplexTypeHelper -// popupURL passed to webController:shouldBlockPopupWithURL:sourceURL: -// Used for testing. -@property(nonatomic, assign) GURL popupURL; -// sourceURL passed to webController:shouldBlockPopupWithURL:sourceURL: -// Used for testing. -@property(nonatomic, assign) GURL sourceURL; // Whether or not the delegate should block popups. @property(nonatomic, assign) BOOL blockPopups; // A web controller that will be returned by webPageOrdered... methods. @property(nonatomic, assign) CRWWebController* childWebController; -// Blocked popup info received in |webController:didBlockPopup:| call. -// nullptr if that delegate method was not called. -@property(nonatomic, readonly) web::BlockedPopupInfo* blockedPopupInfo; + +// Values of arguments passed to +// |webController:createWebControllerForURL:openerURL:initiatedByUser:|. +@property(nonatomic, readonly) CRWWebController* webController; +@property(nonatomic, readonly) GURL childURL; +@property(nonatomic, readonly) GURL openerURL; +@property(nonatomic, readonly) BOOL initiatedByUser; @end -@implementation MockInteractionLoader { - // Backs up the property with the same name. - std::unique_ptr<web::BlockedPopupInfo> _blockedPopupInfo; -} -@synthesize popupURL = _popupURL; -@synthesize sourceURL = _sourceURL; +@implementation MockInteractionLoader + @synthesize blockPopups = _blockPopups; @synthesize childWebController = _childWebController; - -typedef void (^webPageOrderedOpenBlankBlockType)(); -typedef void (^webPageOrderedOpenBlockType)(const GURL&, - const web::Referrer&, - NSString*, - BOOL); +@synthesize webController = _webController; +@synthesize childURL = _childURL; +@synthesize openerURL = _openerURL; +@synthesize initiatedByUser = _initiatedByUser; - (instancetype)initWithRepresentedObject:(id)representedObject { self = [super initWithRepresentedObject:representedObject]; @@ -94,18 +85,16 @@ return self; } -- (CRWWebController*)webPageOrderedOpen { - static_cast<webPageOrderedOpenBlankBlockType>([self blockForSelector:_cmd])(); - return _childWebController; -} +- (CRWWebController*)webController:(CRWWebController*)webController + createWebControllerForURL:(const GURL&)childURL + openerURL:(const GURL&)openerURL + initiatedByUser:(BOOL)initiatedByUser { + _webController = webController; + _childURL = childURL; + _openerURL = openerURL; + _initiatedByUser = initiatedByUser; -- (CRWWebController*)webPageOrderedOpen:(const GURL&)url - referrer:(const web::Referrer&)referrer - windowName:(NSString*)windowName - inBackground:(BOOL)inBackground { - static_cast<webPageOrderedOpenBlockType>([self blockForSelector:_cmd])( - url, referrer, windowName, inBackground); - return _childWebController; + return (_blockPopups && !initiatedByUser) ? nil : _childWebController; } typedef BOOL (^openExternalURLBlockType)(const GURL&); @@ -116,22 +105,6 @@ } - (BOOL)webController:(CRWWebController*)webController - shouldBlockPopupWithURL:(const GURL&)popupURL - sourceURL:(const GURL&)sourceURL { - self.popupURL = popupURL; - self.sourceURL = sourceURL; - return _blockPopups; -} - -- (void)webController:(CRWWebController*)webController - didBlockPopup:(const web::BlockedPopupInfo&)blockedPopupInfo { - _blockedPopupInfo.reset(new web::BlockedPopupInfo(blockedPopupInfo)); -} - -- (web::BlockedPopupInfo*)blockedPopupInfo { - return _blockedPopupInfo.get(); -} -- (BOOL)webController:(CRWWebController*)webController shouldOpenURL:(const GURL&)URL mainDocumentURL:(const GURL&)mainDocumentURL linkClicked:(BOOL)linkClicked { @@ -911,7 +884,7 @@ child_web_state_->GetNavigationManagerImpl().SetSessionController( sessionController); - LoadHtml(@"<html><body></body></html>"); + LoadHtml(@"<html><body></body></html>", GURL("http://test")); } void TearDown() override { EXPECT_OCMOCK_VERIFY(delegate_); @@ -941,76 +914,57 @@ EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); - EXPECT_FALSE([delegate_ blockedPopupInfo]); + EXPECT_FALSE([delegate_ webController]); + EXPECT_FALSE([delegate_ childURL].is_valid()); + EXPECT_FALSE([delegate_ openerURL].is_valid()); + EXPECT_FALSE([delegate_ initiatedByUser]); } // Tests that window.open triggered by user gesture opens a new non-popup // window. TEST_F(CRWWebControllerWindowOpenTest, OpenWithUserGesture) { - SEL selector = @selector(webPageOrderedOpen); - [delegate_ onSelector:selector - callBlockExpectation:^(){ - }]; - [web_controller() touched:YES]; EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); - EXPECT_FALSE([delegate_ blockedPopupInfo]); + + EXPECT_EQ(web_controller(), [delegate_ webController]); + EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); + EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); + EXPECT_TRUE([delegate_ initiatedByUser]); } // Tests that window.open executed w/o user gesture does not open a new window. // Once the blocked popup is allowed a new window is opened. TEST_F(CRWWebControllerWindowOpenTest, AllowPopup) { - SEL selector = - @selector(webPageOrderedOpen:referrer:windowName:inBackground:); - [delegate_ onSelector:selector - callBlockExpectation:^(const GURL& new_window_url, - const web::Referrer& referrer, - NSString* obsoleted_window_name, - BOOL in_background) { - EXPECT_EQ("javascript:void(0);", new_window_url.spec()); - EXPECT_EQ("", referrer.url.spec()); - EXPECT_FALSE(in_background); - }]; - ASSERT_FALSE([web_controller() userIsInteracting]); EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); - base::test::ios::WaitUntilCondition(^bool() { - return [delegate_ blockedPopupInfo]; - }); - if ([delegate_ blockedPopupInfo]) - [delegate_ blockedPopupInfo]->ShowPopup(); - - EXPECT_EQ("", [delegate_ sourceURL].spec()); - EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); + EXPECT_EQ(web_controller(), [delegate_ webController]); + EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); + EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); + EXPECT_FALSE([delegate_ initiatedByUser]); } // Tests that window.open executed w/o user gesture opens a new window, assuming // that delegate allows popups. TEST_F(CRWWebControllerWindowOpenTest, DontBlockPopup) { [delegate_ setBlockPopups:NO]; - SEL selector = @selector(webPageOrderedOpen); - [delegate_ onSelector:selector - callBlockExpectation:^(){ - }]; - EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM()); - EXPECT_FALSE([delegate_ blockedPopupInfo]); - EXPECT_EQ("", [delegate_ sourceURL].spec()); - EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); + EXPECT_EQ(web_controller(), [delegate_ webController]); + EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); + EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); + EXPECT_FALSE([delegate_ initiatedByUser]); } // Tests that window.open executed w/o user gesture does not open a new window. TEST_F(CRWWebControllerWindowOpenTest, BlockPopup) { ASSERT_FALSE([web_controller() userIsInteracting]); EXPECT_NSEQ([NSNull null], OpenWindowByDOM()); - base::test::ios::WaitUntilCondition(^bool() { - return [delegate_ blockedPopupInfo]; - }); - EXPECT_EQ("", [delegate_ sourceURL].spec()); - EXPECT_EQ("javascript:void(0);", [delegate_ popupURL].spec()); + EXPECT_EQ(web_controller(), [delegate_ webController]); + EXPECT_EQ("javascript:void(0);", [delegate_ childURL].spec()); + EXPECT_EQ("http://test/", [delegate_ openerURL].spec()); + EXPECT_FALSE([delegate_ initiatedByUser]); }; // Fixture class to test WKWebView crashes.
diff --git a/net/docs/life-of-a-feature.md b/net/docs/life-of-a-feature.md new file mode 100644 index 0000000..163947b --- /dev/null +++ b/net/docs/life-of-a-feature.md
@@ -0,0 +1,330 @@ +# Life of a Feature + +In the years since the Chromium browser was first open-sourced, the `//net` +directory has expanded from being the basis of loading web content in the +Chromium browser to accommodating a wide variety of networking needs, +both in the Chromium browser and in other Google and third-party products +and projects. + +This brings with it many new opportunities, such as the ability to +introduce new protocols rapidly or push Web security forward, as well as +new challenges, such as how to balance the needs of various `//net` +consumers effectively. + +To make it easier to contribute new features or to change existing +behaviors in `//net`, this document tries to capture the life of a +feature in `//net`, from initial design to the eventual possibility of +deprecation and removal. + +## Supported Projects + +When considering the introduction of a new `//net` feature or changing +a `//net` behavior, it's first necessary to understand where `//net` +is used, how it is used, and what the various constraints and limits are. + +To understand a more comprehensive matrix of the supported platforms and +constraints, see [Supported Projects](supported-projects.md). When +examining a new feature request, or a change in behavior, it's necessary +to consider dimensions such as: + + * Does this feature apply to all supported projects, or is this something + like a Browser-only feature? + * Does this feature apply to all supported platforms, or is this something + specific to a particular subset? + * Is the feature a basic networking library feature, or is it specific to + something in the Web Platform? + * Will some projects wish to strip the feature in order to meet targets + such as memory usage (RAM) or binary size? + * Does it depend on Google services or Google-specific behaviors or + features? + * How will this feature be tested / experimented with? For example, + __Field Trials (Finch)__ and __User Metrics (UMA)__ may not be available + on a number of platforms. + * How risky is the feature towards compatibility/stability? How will it + be undone if there is a bug? + * Are the power/memory/CPU/bandwidth requirements appropriate for the + targeted projects and/or platforms? + +## Design and Layering + +Once the supported platforms and constraints are identified, it's necessary +to determine how to actually design the feature to meet those constraints, +in hopefully the easiest way possible both for implementation and consumption. + +### Designing for multiple platforms + +In general, `//net` features try to support all platforms with a common +interface, and generally eschew OS-specific interfaces from being exposed as +part of `//net`. + +Cross-platform code is generally done via declaring an interface named +`foo.h`, which is common for all platforms, and then using the build-system to +do compile-time switching between implementations in `foo_win.cc`, `foo_mac.cc`, +`foo_android.cc`, etc. + +The goal is to ensure that consumers generally don't have to think about +OS-specific considerations, and can instead code to the interface. + +### Designing for multiple products + +While premature abstraction can significantly harm readability, if it is +anticipated that different products will have different implementation needs, +or may wish to selectively disable the feature, it's often necessary to +abstract that interface sufficiently in `//net` to allow for dependency +injection. + +This is true whether discussing concrete classes and interfaces or something +as simple a boolean configuration flag that different consumers wish to set +differently. + +The two most common approaches in `//net` are injection and delegation. + +#### Injection + +Injection refers to the pattern of defining the interface or concrete +configuration parameter (such as a boolean), along with the concrete +implementation, but requiring the `//net` embedder to supply an instance +of the interface or the configuration parameters (perhaps optionally). + +Examples of this pattern include things such as the `ProxyConfigService`, +which has concrete implementations in `//net` for a variety of platforms' +configuration of proxies, but which requires it be supplied as part of the +`URLRequestContextGetter` building, if proxies are going to be supported. + +An example of injecting configuration flags can be seen in the +`HttpNetworkSession::Params` structure, which is used to provide much of +the initialization parameters for the HTTP layer. + +The ideal form of injection is to pass ownership of the injected object, +such as via a `std::unique_ptr<Foo>`. While this is not consistently +applied in `//net`, as there are a number of places in which ownership is +either shared or left to the embedder, with the injected object passed +around as a naked/raw pointer, this is generally seen as an anti-pattern +and not to be mirrored for new features. + +#### Delegation + +Delegation refers to forcing the `//net` embedder to respond to specific +delegated calls via a Delegate interface that it implements. In general, +when using the delegate pattern, ownership of the delegate should be +transferred, so that the lifetime and threading semantics are clear and +unambiguous. + +That is, for a given class `Foo`, which has a `Foo::Delegate` interface +defined to allow embedders to alter behavior, prefer a constructor that +is +``` +explicit Foo(std::unique_ptr<Delegate> delegate); +``` +so that it is clear that the lifetime of `delegate` is determined by +`Foo`. + +While this may appear similar to Injection, the general difference +between the two approaches is determining where the bulk of the +implementation lies. With Injection, the interface describes a +behavior contract that concrete implementations must adhere to; this +allows for much more flexibility with behavior, but with the downside +of significantly more work to implement or extend. Delegation attempts +to keep the bulk of the implementation in `//net`, and the decision as +to which implementation to use in `//net`, but allows `//net` to +provide specific ways in which embedders can alter behaviors. + +The most notable example of the delegate pattern is `URLRequest::Delegate`, +which keeps the vast majority of the loading logic within `URLRequest`, +but allows the `URLRequest::Delegate` to participate during specific times +in the request lifetime and alter specific behaviors as necessary. (Note: +`URLRequest::Delegate`, like much of the original `//net` code, doesn't +adhere to the recommended lifetime patterns of passing ownership of the +Delegate. It is from the experience debugging and supporting these APIs +that the `//net` team strongly encourages all new code pass explicit +ownership, to reduce the complexity and risk of lifetime issues). + +While the use of a `base::Callback` can also be considered a form of +delegation, the `//net` layer tries to eschew any callbacks that can be +called more than once, and instead favors defining class interfaces +with concrete behavioral requirements in order to ensure the correct +lifetimes of objects and to adjust over time. When `//net` takes a +callback (e.g. `net::CompletionCallback`), the intended pattern is to +signal the asynchronous completion of a single method, invoking that +callback at most once before deallocating it. For more discussion +of these patterns, see [Code Patterns](code-patterns.md). + +### Understanding the Layering + +A significant challenge many feature proposals face is understanding the +layering in `//net` and what different portions of `//net` are allowed to +know. + +#### Socket Pools + +The most common challenge feature proposals encounter is the awareness +that the act of associating an actual request to make with a socket is +done lazily, referred to as "late-binding". + +With late-bound sockets, a given `URLRequest` will not be assigned an actual +transport connection until the request is ready to be sent. This allows for +reprioritizing requests as they come in, to ensure that higher priority requests +get preferential treatment, but it also means that features or data associated +with a `URLRequest` generally don't participate in socket establishment or +maintenance. + +For example, a feature that wants to associate the low-level network socket +with a `URLRequest` during connection establishment is not something that the +`//net` design supports, since the `URLRequest` is kept unaware of how sockets +are established by virtue of the socket pools and late binding. This allows for +more flexibility when working to improve performance, such as the ability to +coalesce multiple logical 'sockets' over a single HTTP/2 or QUIC stream, which +may only have a single physical network socket involved. + +#### Making Additional Requests + +From time to time, `//net` feature proposals will involve needing to load +a secondary resource as part of processing. For example, SDCH involves loading +additional dictionaries that are advertised in a header, and other feature +proposals have involved fetching a `/.well-known/` URI or reporting errors to +a particular URL. + +This is particularly challenging, because often, these features are implemented +deeper in the network stack, such as [`//net/cert`](../cert), [`//net/http`](../http), +or [`//net/filter`](../filter), which [`//net/url_request`](../url_request) depends +on. Because `//net/url_request` depends on these low-level directories, it would +be a circular dependency to have these directories depend on `//net/url_request`, +and circular dependencies are forbidden. + +The recommended solution to address this is to adopt the delegation or injection +patterns. The lower-level directory will define some interface that represents the +"I need this URL" request, and then elsewhere, in a directory allowed to depend +on `//net/url_request`, an implementation of that interface/delegate that uses +`//net/url_request` is implemented. + +### Understanding the Lifetimes + +Understanding the object lifetime and dependency graph can be one of the largest +challenges to contributing and maintaining `//net`. As a consequence, features +which require introducing more complexity to the lifetimes of objects generally +have a greater challenge to acceptance. + +The `//net` stack is designed heavily around a sync-or-async pattern, as +documented in [Code Patterns](code-patterns.md), while also having a strong +requirement that it be possible to cleanly shutdown the network stack. As a +consequence, features should have precise, well-defined lifetime semantics +and support graceful cleanup. Further, because much of the network stack can +have web-observable side-effects, it is often required for tasks to have +defined sequencing that cannot be reordered. To be ensure these requirements +are met, features should attempt to model object lifetimes as a hierarchical +DAG, using explicit ownership and avoiding the use of reference counting or +weak pointers as part of any of the exposed API contracts (even for features +only consumed in `//net`). Features that pay close attention to the lifetime +semantics are more likely to be reviewed and accepted than those that leave +it ambiguous. + +In addition to preferring explicit lifetimes, such as through judicious use of +`std::unique_ptr<>` to indicate ownership transfer of dependencies, many +features in `//net` also expect that if a `base::Callback` is involved (which +includes `net::CompletionCallback`), then it's possible that invoking the +callback may result in the deletion of the current (calling) object. As +further expanded upon in [Code Patterns](code-patterns.md), features and +changes should be designed such that any callback invocation is the last +bit of code executed, and that the callback is accessed via the stack (such +as through the use of either `base::ResetAndReturn(callback_).Run()` or +`std::move(callback_).Run()`. + +### Specs: What Are They Good For + +As `//net` is used as the basis for a number of browsers, it's an important part +of the design philosophy to ensure behaviors are well-specified, and that the +implementation conforms to those specifications. This may be seen as burdensome +when it's unclear whether or not a feature will 'take off,' but it's equally +critical to ensure that the Chromium projects do not fork the Web Platform. + +#### Incubation Is Required + +`//net` respects Chromium's overall position of [incubation first](https://groups.google.com/a/chromium.org/d/msg/blink-dev/PJ_E04kcFb8/baiLN3DTBgAJ) standards development. + +With an incubation first approach, before introducing any new features that +might be exposed over the wire to servers, whether they are explicit behaviors, +such as adding new headers, or implicit behaviors such as +[Happy Eyeballs](https://tools.ietf.org/html/rfc6555), should have some form +of specification written. That specification should at least be on an +incubation track, and the expectation is that the specification should have a +direct path to an appropriate standards track. Features which don't adhere to +this pattern, or which are not making progress towards a standards track, will +require high-level approvals, to ensure that the Platform doesn't fragment. + +#### Introducing New Headers + +A common form of feature request is the introduction of new headers, either via +the `//net` implementation directly, or through consuming `//net` interfaces +and modifying headers on the fly. + +The introduction of any additional headers SHOULD have an incubated spec attached, +ideally with cross-vendor interest. Particularly, headers which only apply to +Google or Google services are very likely to be rejected outright. + +#### Making Additional Requests + +While it's necessary to provide abstraction around `//net/url_request` for +any lower-level components that may need to make additional requests, for most +features, that's not all that is necessary. Because `//net/url_request` only +provides a basic HTTP fetching mechanism, it's insufficient for any Web Platform +feature, because it doesn't consider the broader platform concerns such as +interactions with CORS, Service Workers, cookie and authentication policies, or +even basic interactions with optional features like Extensions or SafeBrowsing. + +To account for all of these things, any resource fetching that is to support +a feature of the Web Platform, whether because the resource will be directly +exposed to web content (for example, an image load or prefetch) or because it +is in response to invoking a Web Platform API (for example, invoking the +credential management API), the feature's resource fetching should be +explainable in terms of the [Fetch Living Standard](https://fetch.spec.whatwg.org/). +The Fetch standard defines a JavaScript API for fetching resources, but more +importantly, defines a common set of infrastructure and terminology that +tries to define how all resource loads in the Web Platform happen - whether +it be through the JavaScript API, through `XMLHttpRequest`, or the `src` +attribute in HTML tags, for example. + +This also includes any resource fetching that wishes to use the same socket +pools or caches as the Web Platform, to ensure that every resource that is +web exposed (directly or indirectly) is fetched in a consistent and +well-documented way, thus minimizing platform fragmentation and security +issues. + +There are exceptions to this, however, but they're generally few and far +between. In general, any feature that needs to define an abstraction to +allow it to "fetch resources," likely needs to also be "explained in terms +of Fetch". + +## Implementation + +In general, prior to implementing, try to get a review on net-dev@chromium.org +for the general feedback and design review. + +In addition to the net-dev@chromium.org early review, `//net` requires that any +browser-exposed behavior should also adhere to the +[Blink Process](https://www.chromium.org/blink#new-features), which includes an +"Intent to Implement" message to blink-dev@chromium.org + +For features that are unclear about their future, such as experiments or trials, +it's also expected that the design planning will also account for how features +will be removed cleanly. For features that radically affect the architecture of +`//net`, expect a high bar of justification, since reversing those changes if +they fail to pan out can cause significant disruption to productivity and +stability. + +## Deprecation + +Plan for obsolence, hope for success. Similar to implementation, features that +are to be removed should also go through the +[Blink Process](https://www.chromium.org/blink#TOC-Web-Platform-Changes:-Process) +for removing features. + +Note that due to the diversity of [Supported Projects](supported-projects.md), +removing a feature while minimizing disruption can be just as complex as adding +a feature. For example, relying solely on __User Metrics (UMA)__ to signal the +safety of removing a feature may not consider all projects, and relying on +__Field Trials (Finch)__ to assess risk or restore the 'legacy' behavior may not +work on all projects either. + +It's precisely because of these challenges that there's such a high bar for +adding features, because they may represent multi-year commitments to support, +even when the feature itself is deprecated or targeted for removal.
diff --git a/net/docs/supported-projects.md b/net/docs/supported-projects.md new file mode 100644 index 0000000..1403dc3 --- /dev/null +++ b/net/docs/supported-projects.md
@@ -0,0 +1,124 @@ +# Supported Projects + +The `//net` stack is used on a variety of platforms and in a variety of open +source projects. These different platforms and projects have differing +degrees of support from `//net` OWNERS as well as differing requirements for +designs and technical requirements. + +Note that this is a rough high-level overview of the major projects; as more +of `//net` is broken into consumable services/components as part of the Mojo +servicificaiton efforts, it's likely that there will be a larger number of +'variants' of these projects with different constraints and features. + +## Google Chrome Browser + +The Google Chrome browser, which lives in `//chrome`, is the most important +`//net` consumer and shapes many of the core design decisions. In general, +features that are not intended with or not compatible with the needs of +the Google Chrome browser will have a very high bar for acceptance in `//net`. + +The feature matrix + + * **Supported Platforms**: Windows, macOS, Linux, Chromium OS, iOS, Android + * **Release Frequency**: ~6 weeks between releases + * **Automatic Updates**: Yes + * **Command-line Flags**: + * __Yes__: Windows, macOS, Linux, Chromium OS (Dev image), Android (rooted) + * __No__: Chromium OS (Release image), iOS, Android (Release) + * **Field Trials (Finch)**: Yes + * **Enterprise Policy**: Yes + * **User Metrics (UMA)**: Yes + * **Component Updater**: Yes + +## Chromium Browser + +The Chromium browser refers to the practice of certain Linux distributions to +bundle the open-source components of Chrome Browser in `//chrome`, branded +as Chromium. This version is not distributed by Google, but by individual +Linux distributions (primarily). Other distributions based on building Chromium +for other platforms exist, although do not see as wide of usage. + + * **Supported Platforms**: Windows, macOS, Linux, Chromium OS, iOS, Android + * **Release Frequency**: Varies by distributor; some Linux distributions + treat versions of Chromium as "Long Term Stable" and support a single + version for a longer time than the Chromium projects do, others track + the Google Chrome release frequency. + * **Automatic Updates**: Varies by distributor + * **Command-line Flags**: + * __Yes__: Windows, macOS, Linux, Chromium OS (dev image), Android (rooted) + * __No__: Chromium OS (Release image), iOS, Android (Release) + * **Field Trials (Finch)**: No + * **Enterprise Policy**: Yes + * **User Metrics (UMA)**: Varies by distributor + * **Component Updater**: Varies by distributor + +## Android WebView + +Distinct from the Chromium browser, the Android WebView is itself based on +the Chromium browser. On official Android devices running Android N or later, +WebView is automatically updated when Google Chrome is updated on the +device. For earlier devices, Android WebView is updated by the System WebView +component. + +Android WebView may also be used on non-official Android devices, such as +those based on the Android Open Source Project but do not go through the +Android [Compatability Test Suite](https://source.android.com/compatibility/cts/). +Such releases have limited to no interaction with the Chromium projects, and +so their capabilities cannot be conclusively documented. + +For official Android devices, WebView has the following capabilities. + + * **Supported Platforms**: Android + * **Release Frequency**: ~6 weeks between releases + * **Automatic Updates**: Varies. Updates are made available on the Android + App Store, but users must explicitly choose to update. As such, the + rate of update varies much more than for the Chromium browser. + * **Command-line Flags**: No + * **Field Trials (Finch)**: No + * **Enterprise Policy**: No + * **User Metrics (UMA)**: No + * **Component Updater**: No + +## `//content` Embedders + +In addition to Chromium, there are a number of other of embedders of +`//content`, such as projects like [Chromium Embedded Framework](https://bitbucket.org/chromiumembedded/cef) +or [Electron](http://electron.atom.io/). While `//net` does not directly +support these consumers, it does support the `//content` embedding API that +these projects use. Note that this excludes the +[content_shell](../../content/shell) test framework. + + * **Supported Platforms**: Windows, macOS, Linux, Chromium OS, iOS, Android + * **Release Frequency**: Varies by consumer; Officially ~6 weeks + * **Command-line Flags**: Varies by consumer + * **Field Trials (Finch)**: No + * **Enterprise Policy**: No + * **User Metrics (UMA)**: No + * **Component Updater**: No + +## Cronet + +[Cronet](../../components/cronet/README.md) is a version of the `//net` +network stack for use in mobile applications on iOS and Android. While +primarily targetting first-party Google applications, Cronet's status as an +open-source project, similar to the Chromium browser, means that it may +find itself embedded in a variety of other projects. + +Unlike some of the other `//net` consumers, Cronet does not necessarily +implement "The Web Platform" (as the holistic set of user agent-focused +features), and instead is more akin to an HTTP(s) client networking library. + + * **Supported Platforms**: iOS, Android + * **Release Frequency**: Varies. While "releases" are made following the + same frequency as Google Chrome, because it is treated similar to + a "third-party" library, different products and projects will ship + different versions of Cronet for differing periods of time. + * **Command-line Flags**: No + * **Field Trials (Finch)**: No + * **Enterprise Policy**: No + * **User Metrics (UMA)**: + * __Yes__: First-party (Google) projects, although they will be + reported in project-specific buckets (e.g. no overarching set of + metrics for all Cronet consumers). + * __No__: In general + * **Component Updater**: No
diff --git a/remoting/base/oauth_token_getter.cc b/remoting/base/oauth_token_getter.cc index ba9bb58..ed571324 100644 --- a/remoting/base/oauth_token_getter.cc +++ b/remoting/base/oauth_token_getter.cc
@@ -6,7 +6,9 @@ namespace remoting { -OAuthTokenGetter::OAuthCredentials::OAuthCredentials( +// OAuthAuthorizationCredentials implementation. + +OAuthTokenGetter::OAuthAuthorizationCredentials::OAuthAuthorizationCredentials( const std::string& login, const std::string& refresh_token, bool is_service_account) @@ -14,4 +16,18 @@ refresh_token(refresh_token), is_service_account(is_service_account) {} +OAuthTokenGetter::OAuthAuthorizationCredentials:: + ~OAuthAuthorizationCredentials() {} + +// OAuthIntermediateCredentials implementation. + +OAuthTokenGetter::OAuthIntermediateCredentials::OAuthIntermediateCredentials( + const std::string& authorization_code, + bool is_service_account) + : authorization_code(authorization_code), + is_service_account(is_service_account) {} + +OAuthTokenGetter::OAuthIntermediateCredentials:: + ~OAuthIntermediateCredentials() {} + } // namespace remoting
diff --git a/remoting/base/oauth_token_getter.h b/remoting/base/oauth_token_getter.h index 8df65ce..80f9cbf 100644 --- a/remoting/base/oauth_token_getter.h +++ b/remoting/base/oauth_token_getter.h
@@ -30,15 +30,22 @@ const std::string& access_token)> TokenCallback; - // This structure contains information required to perform - // authentication to OAuth2. - struct OAuthCredentials { + typedef base::Callback<void(const std::string& user_email, + const std::string& refresh_token)> + CredentialsUpdatedCallback; + + // This structure contains information required to perform authorization + // with the authorization server. + struct OAuthAuthorizationCredentials { + // |login| is used to valdiate |refresh_token| match. // |is_service_account| should be True if the OAuth refresh token is for a // service account, False for a user account, to allow the correct client-ID // to be used. - OAuthCredentials(const std::string& login, - const std::string& refresh_token, - bool is_service_account); + OAuthAuthorizationCredentials(const std::string& login, + const std::string& refresh_token, + bool is_service_account); + + ~OAuthAuthorizationCredentials(); // The user's account name (i.e. their email address). std::string login; @@ -50,6 +57,30 @@ bool is_service_account; }; + // This structure contains information required to perform authentication + // with the authorization server. + struct OAuthIntermediateCredentials { + // |authorization_code| is a one time use code used to authenticate with + // the authorization server. + // |is_service_account| should be True if the OAuth refresh token is for a + // service account, False for a user account, to allow the correct client-ID + // to be used. + OAuthIntermediateCredentials(const std::string& authorization_code, + bool is_service_account); + + ~OAuthIntermediateCredentials(); + + // Code used to check out a access token from the authrozation service. + std::string authorization_code; + + // Override uri for oauth redirect. This is used for client accounts only + // and is optionally set to override the default used for authentication. + std::string oauth_redirect_uri; + + // Whether these credentials belong to a service account. + bool is_service_account; + }; + OAuthTokenGetter() {} virtual ~OAuthTokenGetter() {}
diff --git a/remoting/base/oauth_token_getter_impl.cc b/remoting/base/oauth_token_getter_impl.cc index 9a8e384..4f49a455 100644 --- a/remoting/base/oauth_token_getter_impl.cc +++ b/remoting/base/oauth_token_getter_impl.cc
@@ -12,6 +12,7 @@ #include "google_apis/google_api_keys.h" #include "net/url_request/url_request_context_getter.h" #include "remoting/base/logging.h" +#include "remoting/base/oauth_helper.h" namespace remoting { @@ -26,11 +27,27 @@ } // namespace OAuthTokenGetterImpl::OAuthTokenGetterImpl( - std::unique_ptr<OAuthCredentials> oauth_credentials, + std::unique_ptr<OAuthIntermediateCredentials> intermediate_credentials, + const OAuthTokenGetter::CredentialsUpdatedCallback& on_credentials_update, const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter, bool auto_refresh) - : oauth_credentials_(std::move(oauth_credentials)), + : intermediate_credentials_(std::move(intermediate_credentials)), + gaia_oauth_client_( + new gaia::GaiaOAuthClient(url_request_context_getter.get())), + credentials_updated_callback_(on_credentials_update), + url_request_context_getter_(url_request_context_getter) { + if (auto_refresh) { + refresh_timer_.reset(new base::OneShotTimer()); + } +} + +OAuthTokenGetterImpl::OAuthTokenGetterImpl( + std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials, + const scoped_refptr<net::URLRequestContextGetter>& + url_request_context_getter, + bool auto_refresh) + : authorization_credentials_(std::move(authorization_credentials)), gaia_oauth_client_( new gaia::GaiaOAuthClient(url_request_context_getter.get())), url_request_context_getter_(url_request_context_getter) { @@ -41,47 +58,62 @@ OAuthTokenGetterImpl::~OAuthTokenGetterImpl() {} -void OAuthTokenGetterImpl::OnGetTokensResponse(const std::string& user_email, +void OAuthTokenGetterImpl::OnGetTokensResponse(const std::string& refresh_token, const std::string& access_token, int expires_seconds) { - NOTREACHED(); + DCHECK(CalledOnValidThread()); + DCHECK(intermediate_credentials_); + VLOG(1) << "Received OAuth tokens."; + + // Update the access token and any other auto-update timers. + UpdateAccessToken(access_token, expires_seconds); + + // Keep the refresh token in the authorization_credentials. + authorization_credentials_.reset( + new OAuthTokenGetter::OAuthAuthorizationCredentials( + std::string(), refresh_token, + intermediate_credentials_->is_service_account)); + + // Clear out the one time use token. + intermediate_credentials_.reset(); + + // At this point we don't know the email address so we need to fetch it. + email_discovery_ = true; + gaia_oauth_client_->GetUserEmail(access_token, kMaxRetries, this); } void OAuthTokenGetterImpl::OnRefreshTokenResponse( const std::string& access_token, int expires_seconds) { DCHECK(CalledOnValidThread()); - DCHECK(oauth_credentials_.get()); + DCHECK(authorization_credentials_); VLOG(1) << "Received OAuth token."; - oauth_access_token_ = access_token; - base::TimeDelta token_expiration = - base::TimeDelta::FromSeconds(expires_seconds) - - base::TimeDelta::FromSeconds(kTokenUpdateTimeBeforeExpirySeconds); - auth_token_expiry_time_ = base::Time::Now() + token_expiration; + // Update the access token and any other auto-update timers. + UpdateAccessToken(access_token, expires_seconds); - if (refresh_timer_) { - refresh_timer_->Stop(); - refresh_timer_->Start(FROM_HERE, token_expiration, this, - &OAuthTokenGetterImpl::RefreshOAuthToken); - } - - if (!oauth_credentials_->is_service_account && !email_verified_) { + if (!authorization_credentials_->is_service_account && !email_verified_) { gaia_oauth_client_->GetUserEmail(access_token, kMaxRetries, this); } else { - refreshing_oauth_token_ = false; - NotifyCallbacks(OAuthTokenGetterImpl::SUCCESS, oauth_credentials_->login, - oauth_access_token_); + response_pending_ = false; + NotifyTokenCallbacks(OAuthTokenGetterImpl::SUCCESS, + authorization_credentials_->login, + oauth_access_token_); } } void OAuthTokenGetterImpl::OnGetUserEmailResponse( const std::string& user_email) { DCHECK(CalledOnValidThread()); - DCHECK(oauth_credentials_.get()); + DCHECK(authorization_credentials_); VLOG(1) << "Received user info."; - if (user_email != oauth_credentials_->login) { + if (email_discovery_) { + authorization_credentials_->login = user_email; + email_discovery_ = false; + NotifyUpdatedCallbacks(authorization_credentials_->login, + authorization_credentials_->refresh_token); + } else if (user_email != authorization_credentials_->login) { LOG(ERROR) << "OAuth token and email address do not refer to " "the same account."; OnOAuthError(); @@ -89,17 +121,34 @@ } email_verified_ = true; - refreshing_oauth_token_ = false; + response_pending_ = false; // Now that we've refreshed the token and verified that it's for the correct // user account, try to connect using the new token. - NotifyCallbacks(OAuthTokenGetterImpl::SUCCESS, user_email, - oauth_access_token_); + NotifyTokenCallbacks(OAuthTokenGetterImpl::SUCCESS, user_email, + oauth_access_token_); } -void OAuthTokenGetterImpl::NotifyCallbacks(Status status, - const std::string& user_email, - const std::string& access_token) { +void OAuthTokenGetterImpl::UpdateAccessToken(const std::string& access_token, + int expires_seconds) { + oauth_access_token_ = access_token; + base::TimeDelta token_expiration = + base::TimeDelta::FromSeconds(expires_seconds) - + base::TimeDelta::FromSeconds(kTokenUpdateTimeBeforeExpirySeconds); + access_token_expiry_time_ = base::Time::Now() + token_expiration; + + if (refresh_timer_) { + refresh_timer_->Stop(); + refresh_timer_->Start(FROM_HERE, token_expiration, this, + &OAuthTokenGetterImpl::RefreshAccessToken); + } +} + +void OAuthTokenGetterImpl::NotifyTokenCallbacks( + Status status, + const std::string& user_email, + const std::string& access_token) { + DCHECK(CalledOnValidThread()); std::queue<TokenCallback> callbacks(pending_callbacks_); pending_callbacks_ = std::queue<TokenCallback>(); @@ -109,72 +158,123 @@ } } +void OAuthTokenGetterImpl::NotifyUpdatedCallbacks( + const std::string& user_email, + const std::string& refresh_token) { + DCHECK(CalledOnValidThread()); + if (credentials_updated_callback_) { + credentials_updated_callback_.Run(user_email, refresh_token); + } +} + void OAuthTokenGetterImpl::OnOAuthError() { DCHECK(CalledOnValidThread()); LOG(ERROR) << "OAuth: invalid credentials."; - refreshing_oauth_token_ = false; + response_pending_ = false; // Throw away invalid credentials and force a refresh. oauth_access_token_.clear(); - auth_token_expiry_time_ = base::Time(); + access_token_expiry_time_ = base::Time(); email_verified_ = false; - NotifyCallbacks(OAuthTokenGetterImpl::AUTH_ERROR, std::string(), - std::string()); + NotifyTokenCallbacks(OAuthTokenGetterImpl::AUTH_ERROR, std::string(), + std::string()); } void OAuthTokenGetterImpl::OnNetworkError(int response_code) { DCHECK(CalledOnValidThread()); LOG(ERROR) << "Network error when trying to update OAuth token: " << response_code; - refreshing_oauth_token_ = false; - NotifyCallbacks(OAuthTokenGetterImpl::NETWORK_ERROR, std::string(), - std::string()); + response_pending_ = false; + NotifyTokenCallbacks(OAuthTokenGetterImpl::NETWORK_ERROR, std::string(), + std::string()); } void OAuthTokenGetterImpl::CallWithToken(const TokenCallback& on_access_token) { DCHECK(CalledOnValidThread()); - bool need_new_auth_token = - auth_token_expiry_time_.is_null() || - base::Time::Now() >= auth_token_expiry_time_ || - (!oauth_credentials_->is_service_account && !email_verified_); - - if (need_new_auth_token) { + if (intermediate_credentials_) { pending_callbacks_.push(on_access_token); - if (!refreshing_oauth_token_) - RefreshOAuthToken(); + if (!response_pending_) { + GetOauthTokensFromAuthCode(); + } } else { - on_access_token.Run(SUCCESS, oauth_credentials_->login, - oauth_access_token_); + bool need_new_auth_token = + access_token_expiry_time_.is_null() || + base::Time::Now() >= access_token_expiry_time_ || + (!authorization_credentials_->is_service_account && !email_verified_); + + if (need_new_auth_token) { + pending_callbacks_.push(on_access_token); + if (!response_pending_) { + RefreshAccessToken(); + } + } else { + on_access_token.Run(SUCCESS, authorization_credentials_->login, + oauth_access_token_); + } } } void OAuthTokenGetterImpl::InvalidateCache() { DCHECK(CalledOnValidThread()); - auth_token_expiry_time_ = base::Time(); + access_token_expiry_time_ = base::Time(); } -void OAuthTokenGetterImpl::RefreshOAuthToken() { +void OAuthTokenGetterImpl::GetOauthTokensFromAuthCode() { DCHECK(CalledOnValidThread()); - VLOG(1) << "Refreshing OAuth token."; - DCHECK(!refreshing_oauth_token_); + VLOG(1) << "Fetching OAuth token from Auth Code."; + DCHECK(!response_pending_); // Service accounts use different API keys, as they use the client app flow. google_apis::OAuth2Client oauth2_client = - oauth_credentials_->is_service_account ? google_apis::CLIENT_REMOTING_HOST - : google_apis::CLIENT_REMOTING; + intermediate_credentials_->is_service_account + ? google_apis::CLIENT_REMOTING_HOST + : google_apis::CLIENT_REMOTING; + + std::string redirect_uri; + if (intermediate_credentials_->oauth_redirect_uri.empty()) { + if (intermediate_credentials_->is_service_account) { + redirect_uri = "oob"; + } else { + redirect_uri = GetDefaultOauthRedirectUrl(); + } + } else { + redirect_uri = intermediate_credentials_->oauth_redirect_uri; + } + + gaia::OAuthClientInfo client_info = { + google_apis::GetOAuth2ClientID(oauth2_client), + google_apis::GetOAuth2ClientSecret(oauth2_client), redirect_uri}; + + response_pending_ = true; + + gaia_oauth_client_->GetTokensFromAuthCode( + client_info, intermediate_credentials_->authorization_code, kMaxRetries, + this); +} + +void OAuthTokenGetterImpl::RefreshAccessToken() { + DCHECK(CalledOnValidThread()); + VLOG(1) << "Refreshing OAuth Access token."; + DCHECK(!response_pending_); + + // Service accounts use different API keys, as they use the client app flow. + google_apis::OAuth2Client oauth2_client = + authorization_credentials_->is_service_account + ? google_apis::CLIENT_REMOTING_HOST + : google_apis::CLIENT_REMOTING; gaia::OAuthClientInfo client_info = { google_apis::GetOAuth2ClientID(oauth2_client), google_apis::GetOAuth2ClientSecret(oauth2_client), // Redirect URL is only used when getting tokens from auth code. It - // is not required when getting access tokens. + // is not required when getting access tokens from refresh tokens. ""}; - refreshing_oauth_token_ = true; + response_pending_ = true; std::vector<std::string> empty_scope_list; // Use scope from refresh token. gaia_oauth_client_->RefreshToken(client_info, - oauth_credentials_->refresh_token, + authorization_credentials_->refresh_token, empty_scope_list, kMaxRetries, this); }
diff --git a/remoting/base/oauth_token_getter_impl.h b/remoting/base/oauth_token_getter_impl.h index f3d2291e..c725d524 100644 --- a/remoting/base/oauth_token_getter_impl.h +++ b/remoting/base/oauth_token_getter_impl.h
@@ -20,15 +20,29 @@ namespace remoting { -// OAuthTokenGetter caches OAuth access tokens and refreshes them as needed. +// OAuthTokenGetter accepts an authorization code in the intermediate +// credentials or a refresh token in the authorization credentials. It will +// convert authorization code into a refresh token and access token, you may +// pass in a callback to be notified when a refresh token has been updated. +// OAuthTokenGetter will exchange refresh tokens for access tokens and will +// cache access tokens, refreshing them as needed. +// On first usage it is likely an application will only have an auth code, +// from this you can get a refresh token which can be reused next app launch. class OAuthTokenGetterImpl : public OAuthTokenGetter, public base::NonThreadSafe, public gaia::GaiaOAuthClient::Delegate { public: - OAuthTokenGetterImpl(std::unique_ptr<OAuthCredentials> oauth_credentials, - const scoped_refptr<net::URLRequestContextGetter>& - url_request_context_getter, - bool auto_refresh); + OAuthTokenGetterImpl( + std::unique_ptr<OAuthIntermediateCredentials> intermediate_credentials, + const OAuthTokenGetter::CredentialsUpdatedCallback& on_credentials_update, + const scoped_refptr<net::URLRequestContextGetter>& + url_request_context_getter, + bool auto_refresh); + OAuthTokenGetterImpl( + std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials, + const scoped_refptr<net::URLRequestContextGetter>& + url_request_context_getter, + bool auto_refresh); ~OAuthTokenGetterImpl() override; // OAuthTokenGetter interface. @@ -47,19 +61,26 @@ void OnOAuthError() override; void OnNetworkError(int response_code) override; - void NotifyCallbacks(Status status, - const std::string& user_email, - const std::string& access_token); - void RefreshOAuthToken(); + void UpdateAccessToken(const std::string& access_token, int expires_seconds); + void NotifyTokenCallbacks(Status status, + const std::string& user_email, + const std::string& access_token); + void NotifyUpdatedCallbacks(const std::string& user_email, + const std::string& refresh_token); + void GetOauthTokensFromAuthCode(); + void RefreshAccessToken(); - std::unique_ptr<OAuthCredentials> oauth_credentials_; + std::unique_ptr<OAuthIntermediateCredentials> intermediate_credentials_; + std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials_; std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; + OAuthTokenGetter::CredentialsUpdatedCallback credentials_updated_callback_; scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; - bool refreshing_oauth_token_ = false; + bool response_pending_ = false; bool email_verified_ = false; + bool email_discovery_ = false; std::string oauth_access_token_; - base::Time auth_token_expiry_time_; + base::Time access_token_expiry_time_; std::queue<OAuthTokenGetter::TokenCallback> pending_callbacks_; std::unique_ptr<base::OneShotTimer> refresh_timer_; };
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index d4851ad..6c0cfd41 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc
@@ -1355,10 +1355,10 @@ std::unique_ptr<DnsBlackholeChecker> dns_blackhole_checker( new DnsBlackholeChecker(context_->url_request_context_getter(), talkgadget_prefix_)); - std::unique_ptr<OAuthTokenGetter::OAuthCredentials> oauth_credentials( - new OAuthTokenGetter::OAuthCredentials(xmpp_server_config_.username, - oauth_refresh_token_, - use_service_account_)); + std::unique_ptr<OAuthTokenGetter::OAuthAuthorizationCredentials> + oauth_credentials(new OAuthTokenGetter::OAuthAuthorizationCredentials( + xmpp_server_config_.username, oauth_refresh_token_, + use_service_account_)); oauth_token_getter_.reset( new OAuthTokenGetterImpl(std::move(oauth_credentials), context_->url_request_context_getter(), false));
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation index fa4bb572..47a336c 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -9,8 +9,10 @@ crbug.com/551000 virtual/mojo-loading/http/tests/inspector/console-resource-errors.html [ Failure ] # Flipped order between diStartProvisionalLoad & willSendRequest -crbug.com/625765 virtual/mojo-loading/http/tests/loading/redirect-methods.html [ Crash Failure ] +crbug.com/647698 http/tests/loading/307-after-303-after-post.html [ Failure ] crbug.com/625765 http/tests/loading/redirect-methods.html [ Crash Failure ] +crbug.com/647698 virtual/mojo-loading/http/tests/loading/307-after-303-after-post.html [ Failure ] +crbug.com/625765 virtual/mojo-loading/http/tests/loading/redirect-methods.html [ Crash Failure ] # https://crbug.com/555418: Move `X-Frame-Options` and CSP's `frame-ancestor` # checks up out of the renderer. @@ -29,11 +31,6 @@ crbug.com/638900 http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ] crbug.com/638900 virtual/mojo-loading/http/tests/loading/doc-write-sync-third-party-script-reload.html [ Failure ] -# https://crbug.com/647698: Failing due to absence of call to -# WebFrameClient::didReceiveServerRedirectForProvisionalLoad. -crbug.com/647698 http/tests/loading/307-after-303-after-post.html [ Failure ] -crbug.com/647698 virtual/mojo-loading/http/tests/loading/307-after-303-after-post.html [ Failure ] - # Issue with ServiceWorker timing. Bug(none) external/wpt/service-workers/service-worker/navigate-window.https.html [ Failure ] @@ -47,9 +44,11 @@ Bug(none) http/tests/security/location-href-clears-username-password.html [ Failure ] Bug(none) virtual/mojo-loading/http/tests/security/location-href-clears-username-password.html [ Failure ] -# This test seems to be partially failing without PlzNavigate as well. +# Timeout +Bug(none) fast/loader/crash-replacing-location-before-load.html [ Timeout ] # These tests are flaky. +Bug(none) external/wpt/service-workers/service-worker/fetch-event-redirect.https.html [ Crash ] Bug(none) http/tests/misc/window-open-then-write.html [ Timeout ] Bug(none) external/wpt/html/browsers/browsing-the-web/unloading-documents/beforeunload-on-history-back.html [ Failure ] Bug(none) virtual/mojo-loading/http/tests/misc/window-open-then-write.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 74f72b0..32ce71d 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -771,6 +771,10 @@ crbug.com/617152 external/wpt/mediacapture-streams/GUM-impossible-constraint.https.html [ Skip ] +crbug.com/281504 fast/canvas/canvas-large-pattern.html [ Failure ] +crbug.com/281504 virtual/display_list_2d_canvas/fast/canvas/canvas-large-pattern.html [ Failure ] +crbug.com/281504 virtual/gpu/fast/canvas/canvas-large-pattern.html [ Failure ] + crbug.com/417782 [ Linux Win ] virtual/rootlayerscrolls/fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Failure ] crbug.com/492664 [ Linux ] external/csswg-test/css-writing-modes-3/box-offsets-rel-pos-vlr-005.xht [ Failure ] crbug.com/492664 [ Linux ] external/csswg-test/css-writing-modes-3/box-offsets-rel-pos-vrl-004.xht [ Failure ] @@ -1402,6 +1406,7 @@ # These tests are skipped as there is no touch support on Mac. crbug.com/613672 [ Mac ] fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ] crbug.com/613672 [ Mac ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ] +crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Skip ] crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ] crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy-manual.html [ Skip ] crbug.com/613672 [ Mac ] external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction-manual.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding-expected.txt deleted file mode 100644 index 13904cd3..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding-expected.txt +++ /dev/null
@@ -1,59 +0,0 @@ -Series of tests to ensure correct results of the winding rule in isPointInPath. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing default isPointInPath -PASS ctx.isPointInPath(50, 50) is true -PASS ctx.isPointInPath(NaN, 50) is false -PASS ctx.isPointInPath(50, NaN) is false - -Testing nonzero isPointInPath -PASS ctx.isPointInPath(50, 50, 'nonzero') is true - -Testing evenodd isPointInPath -PASS ctx.isPointInPath(50, 50, 'evenodd') is false - -Testing default isPointInPath with Path object -PASS ctx.isPointInPath(path, 50, 50) is true -PASS ctx.isPointInPath(path, 50, 50, undefined) is true -PASS ctx.isPointInPath(path, NaN, 50) is false -PASS ctx.isPointInPath(path, 50, NaN) is false - -Testing nonzero isPointInPath with Path object -PASS ctx.isPointInPath(path, 50, 50, 'nonzero') is true - -Testing evenodd isPointInPath with Path object -PASS ctx.isPointInPath(path, 50, 50, 'evenodd') is false - -Testing invalid enumeration isPointInPath (w/ and w/o Path object -PASS ctx.isPointInPath(path, 50, 50, 'gazonk') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value 'gazonk' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath(50, 50, 'gazonk') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value 'gazonk' is not a valid enum value of type CanvasFillRule.. - -Testing invalid type isPointInPath with Path object -PASS ctx.isPointInPath(null, 50, 50) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value '50' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath(null, 50, 50, 'nonzero') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath(null, 50, 50, 'evenodd') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath(null, 50, 50, null) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath(path, 50, 50, null) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value 'null' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath(undefined, 50, 50) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value '50' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath(undefined, 50, 50, 'nonzero') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath(undefined, 50, 50, 'evenodd') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath(undefined, 50, 50, undefined) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath([], 50, 50) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value '50' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath([], 50, 50, 'nonzero') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath([], 50, 50, 'evenodd') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath({}, 50, 50) threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': The provided value '50' is not a valid enum value of type CanvasFillRule.. -PASS ctx.isPointInPath({}, 50, 50, 'nonzero') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInPath({}, 50, 50, 'evenodd') threw exception TypeError: Failed to execute 'isPointInPath' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. - -Testing extremely large scale -PASS ctx.isPointInPath(0, 0, 'nonzero') is true -PASS ctx.isPointInPath(0, 0, 'evenodd') is true -Check with non-invertible ctm. -PASS ctx.isPointInPath(0, 0, 'nonzero') is false -PASS ctx.isPointInPath(0, 0, 'evenodd') is false -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding.html index 3da36651..82851c0 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInPath-winding.html
@@ -1,8 +1,95 @@ -<!doctype html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> -<script src="script-tests/canvas-isPointInPath-winding.js"></script> -</body> \ No newline at end of file +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> + +var canvas = document.createElement('canvas'); +canvas.width = 200; +canvas.height = 200; +ctx = canvas.getContext('2d'); + +test(function(t) { + // Testing default isPointInPath'); + ctx.beginPath(); + ctx.rect(0, 0, 100, 100); + ctx.rect(25, 25, 50, 50); + assert_true(ctx.isPointInPath(50, 50)); + assert_false(ctx.isPointInPath(NaN, 50)); + assert_false(ctx.isPointInPath(50, NaN)); + + // Testing nonzero isPointInPath'); + ctx.beginPath(); + ctx.rect(0, 0, 100, 100); + ctx.rect(25, 25, 50, 50); + assert_true(ctx.isPointInPath(50, 50, 'nonzero')); + + // Testing evenodd isPointInPath'); + ctx.beginPath(); + ctx.rect(0, 0, 100, 100); + ctx.rect(25, 25, 50, 50); + assert_false(ctx.isPointInPath(50, 50, 'evenodd')); + + // reset path in context + ctx.beginPath(); + + // Testing default isPointInPath with Path object'); + path = new Path2D(); + path.rect(0, 0, 100, 100); + path.rect(25, 25, 50, 50); + assert_true(ctx.isPointInPath(path, 50, 50)); + assert_true(ctx.isPointInPath(path, 50, 50, undefined)); + assert_false(ctx.isPointInPath(path, NaN, 50)); + assert_false(ctx.isPointInPath(path, 50, NaN)); + + // Testing nonzero isPointInPath with Path object'); + path = new Path2D(); + path.rect(0, 0, 100, 100); + path.rect(25, 25, 50, 50); + assert_true(ctx.isPointInPath(path, 50, 50, 'nonzero')); + + // Testing evenodd isPointInPath with Path object'); + path = new Path2D(); + path.rect(0, 0, 100, 100); + path.rect(25, 25, 50, 50); + assert_false(ctx.isPointInPath(path, 50, 50, 'evenodd')); + + // Testing invalid enumeration isPointInPath (w/ and w/o Path object'); + assert_throws(null, function(){ ctx.isPointInPath(path, 50, 50, 'gazonk');}); + assert_throws(null, function(){ ctx.isPointInPath(50, 50, 'gazonk');}); + + // Testing invalid type isPointInPath with Path object'); + assert_throws(null, function(){ ctx.isPointInPath(null, 50, 50);}); + assert_throws(null, function(){ ctx.isPointInPath(null, 50, 50, 'nonzero');}); + assert_throws(null, function(){ ctx.isPointInPath(null, 50, 50, 'evenodd');}); + assert_throws(null, function(){ ctx.isPointInPath(null, 50, 50, null);}); + assert_throws(null, function(){ ctx.isPointInPath(path, 50, 50, null);}); + assert_throws(null, function(){ ctx.isPointInPath(undefined, 50, 50);}); + assert_throws(null, function(){ ctx.isPointInPath(undefined, 50, 50, 'nonzero');}); + assert_throws(null, function(){ ctx.isPointInPath(undefined, 50, 50, 'evenodd');}); + assert_throws(null, function(){ ctx.isPointInPath(undefined, 50, 50, undefined);}); + assert_throws(null, function(){ ctx.isPointInPath([], 50, 50);}); + assert_throws(null, function(){ ctx.isPointInPath([], 50, 50, 'nonzero');}); + assert_throws(null, function(){ ctx.isPointInPath([], 50, 50, 'evenodd');}); + assert_throws(null, function(){ ctx.isPointInPath({}, 50, 50);}); + assert_throws(null, function(){ ctx.isPointInPath({}, 50, 50, 'nonzero');}); + assert_throws(null, function(){ ctx.isPointInPath({}, 50, 50, 'evenodd');}); + + // Testing extremely large scale + ctx.save(); + ctx.scale(Number.MAX_VALUE, Number.MAX_VALUE); + ctx.beginPath(); + ctx.rect(-10, -10, 20, 20); + assert_true(ctx.isPointInPath(0, 0, 'nonzero')); + assert_true(ctx.isPointInPath(0, 0, 'evenodd')); + ctx.restore(); + + // Check with non-invertible ctm. + ctx.save(); + ctx.scale(0, 0); + ctx.beginPath(); + ctx.rect(-10, -10, 20, 20); + assert_false(ctx.isPointInPath(0, 0, 'nonzero')); + assert_false(ctx.isPointInPath(0, 0, 'evenodd')); + ctx.restore(); +}, "Series of tests to ensure correct results of the winding rule in isPointInPath."); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-expected.txt deleted file mode 100644 index 9bbd037..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-expected.txt +++ /dev/null
@@ -1,74 +0,0 @@ -Test the behavior of isPointInStroke in Canvas - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Initial behavior: lineWith = 1.0 -PASS ctx.isPointInStroke(20,20) is true -PASS ctx.isPointInStroke(120,20) is true -PASS ctx.isPointInStroke(20,120) is true -PASS ctx.isPointInStroke(120,120) is true -PASS ctx.isPointInStroke(70,20) is true -PASS ctx.isPointInStroke(20,70) is true -PASS ctx.isPointInStroke(120,70) is true -PASS ctx.isPointInStroke(70,120) is true -PASS ctx.isPointInStroke(22,22) is false -PASS ctx.isPointInStroke(118,22) is false -PASS ctx.isPointInStroke(22,118) is false -PASS ctx.isPointInStroke(118,118) is false -PASS ctx.isPointInStroke(70,18) is false -PASS ctx.isPointInStroke(122,70) is false -PASS ctx.isPointInStroke(70,122) is false -PASS ctx.isPointInStroke(18,70) is false - -Set lineWith = 10.0 -PASS ctx.isPointInStroke(22,22) is true -PASS ctx.isPointInStroke(118,22) is true -PASS ctx.isPointInStroke(22,118) is true -PASS ctx.isPointInStroke(118,118) is true -PASS ctx.isPointInStroke(70,18) is true -PASS ctx.isPointInStroke(122,70) is true -PASS ctx.isPointInStroke(70,122) is true -PASS ctx.isPointInStroke(18,70) is true -PASS ctx.isPointInStroke(26,70) is false -PASS ctx.isPointInStroke(70,26) is false -PASS ctx.isPointInStroke(70,114) is false -PASS ctx.isPointInStroke(114,70) is false - -Check lineJoin = 'bevel' -PASS ctx.isPointInStroke(113,20) is false - -Check lineJoin = 'miter' -PASS ctx.isPointInStroke(113,20) is true - -Check miterLimit = 2.0 -PASS ctx.isPointInStroke(113,20) is false - -Check lineCap = 'butt' -PASS ctx.isPointInStroke(112,10) is false - -Check lineCap = 'round' -PASS ctx.isPointInStroke(112,10) is true -PASS ctx.isPointInStroke(117,10) is false - -Check lineCap = 'square' -PASS ctx.isPointInStroke(112,10) is true -PASS ctx.isPointInStroke(117,10) is false - -Check setLineDash([10,10]) -PASS ctx.isPointInStroke(15,10) is true -PASS ctx.isPointInStroke(25,10) is false -PASS ctx.isPointInStroke(35,10) is true - -Check dashOffset = 10 -PASS ctx.isPointInStroke(15,10) is false -PASS ctx.isPointInStroke(25,10) is true -PASS ctx.isPointInStroke(35,10) is false -Check extremely large scale -PASS ctx.isPointInStroke(0, 0) is true -Check with non-invertible ctm. -PASS ctx.isPointInStroke(0, 0) is false -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path-expected.txt deleted file mode 100644 index dec4240..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path-expected.txt +++ /dev/null
@@ -1,78 +0,0 @@ -Test the behavior of isPointInStroke in Canvas with path object - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Initial behavior: lineWidth = 1.0 -PASS ctx.isPointInStroke(path,20,20) is true -PASS ctx.isPointInStroke(path,120,20) is true -PASS ctx.isPointInStroke(path,20,120) is true -PASS ctx.isPointInStroke(path,120,120) is true -PASS ctx.isPointInStroke(path,70,20) is true -PASS ctx.isPointInStroke(path,20,70) is true -PASS ctx.isPointInStroke(path,120,70) is true -PASS ctx.isPointInStroke(path,70,120) is true -PASS ctx.isPointInStroke(path,22,22) is false -PASS ctx.isPointInStroke(path,118,22) is false -PASS ctx.isPointInStroke(path,22,118) is false -PASS ctx.isPointInStroke(path,118,118) is false -PASS ctx.isPointInStroke(path,70,18) is false -PASS ctx.isPointInStroke(path,122,70) is false -PASS ctx.isPointInStroke(path,70,122) is false -PASS ctx.isPointInStroke(path,18,70) is false -PASS ctx.isPointInStroke(path,NaN,122) is false -PASS ctx.isPointInStroke(path,18,NaN) is false - -Check invalid type -PASS ctx.isPointInStroke(null,70,20) threw exception TypeError: Failed to execute 'isPointInStroke' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInStroke(undefined,70,20) threw exception TypeError: Failed to execute 'isPointInStroke' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInStroke([],20,70) threw exception TypeError: Failed to execute 'isPointInStroke' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS ctx.isPointInStroke({},120,70) threw exception TypeError: Failed to execute 'isPointInStroke' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. - -Set lineWidth = 10.0 -PASS ctx.isPointInStroke(path,22,22) is true -PASS ctx.isPointInStroke(path,118,22) is true -PASS ctx.isPointInStroke(path,22,118) is true -PASS ctx.isPointInStroke(path,118,118) is true -PASS ctx.isPointInStroke(path,70,18) is true -PASS ctx.isPointInStroke(path,122,70) is true -PASS ctx.isPointInStroke(path,70,122) is true -PASS ctx.isPointInStroke(path,18,70) is true -PASS ctx.isPointInStroke(path,26,70) is false -PASS ctx.isPointInStroke(path,70,26) is false -PASS ctx.isPointInStroke(path,70,114) is false -PASS ctx.isPointInStroke(path,114,70) is false - -Check lineJoin = 'bevel' -PASS ctx.isPointInStroke(path,113,20) is false - -Check lineJoin = 'miter' -PASS ctx.isPointInStroke(path,113,20) is true - -Check miterLimit = 2.0 -PASS ctx.isPointInStroke(path,113,20) is false - -Check lineCap = 'butt' -PASS ctx.isPointInStroke(path,112,10) is false - -Check lineCap = 'round' -PASS ctx.isPointInStroke(path,112,10) is true -PASS ctx.isPointInStroke(path,117,10) is false - -Check lineCap = 'square' -PASS ctx.isPointInStroke(path,112,10) is true -PASS ctx.isPointInStroke(path,117,10) is false - -Check setLineDash([10,10]) -PASS ctx.isPointInStroke(path,15,10) is true -PASS ctx.isPointInStroke(path,25,10) is false -PASS ctx.isPointInStroke(path,35,10) is true - -Check dashOffset = 10 -PASS ctx.isPointInStroke(path,15,10) is false -PASS ctx.isPointInStroke(path,25,10) is true -PASS ctx.isPointInStroke(path,35,10) is false -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path.html index 48c355d..3ba08b0 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke-with-path.html
@@ -1,8 +1,113 @@ -<!doctype html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-isPointInStroke-with-path.js"></script> +<script> +var ctx = document.createElement('canvas').getContext('2d'); +document.body.appendChild(ctx.canvas); +ctx.strokeStyle = '#0ff'; + +// Create new path. +var path = new Path2D(); +path.rect(20, 20, 100, 100); + +function testPointInStroke(x, y, isPointInStroke) { + if(isPointInStroke) + assert_true(ctx.isPointInStroke(path, x, y)); + else + assert_false(ctx.isPointInStroke(path, x, y)); +} + +testScenarios1 = + [ + ['TestScenario 1, Case 1', 20, 20, true], + ['TestScenario 1, Case 2', 120, 20, true], + ['TestScenario 1, Case 3', 20, 120, true], + ['TestScenario 1, Case 4', 120, 120, true], + ['TestScenario 1, Case 5', 70, 20, true], + ['TestScenario 1, Case 6', 20, 70, true], + ['TestScenario 1, Case 7', 120, 70, true], + ['TestScenario 1, Case 8', 70, 120, true], + + ['TestScenario 1, Case 9', 22, 22, false], + ['TestScenario 1, Case 10', 118, 22, false], + ['TestScenario 1, Case 11', 22, 118, false], + ['TestScenario 1, Case 12', 118, 118, false], + ['TestScenario 1, Case 13', 70, 18, false], + ['TestScenario 1, Case 14', 122, 70, false], + ['TestScenario 1, Case 15', 70, 122, false], + ['TestScenario 1, Case 16', 18, 70, false], + ['TestScenario 1, Case 17', NaN, 122, false], + ['TestScenario 1, Case 18', 18, NaN, false] + ]; +generate_tests(testPointInStroke, testScenarios1); + +test(function(t) { + assert_throws(new TypeError(), function() {ctx.isPointInStroke(null, 70, 20);}); + assert_throws(new TypeError(), function() {ctx.isPointInStroke(undefined, 70, 20);}); + assert_throws(new TypeError(), function() {ctx.isPointInStroke([], 20, 70);}); + assert_throws(new TypeError(), function() {ctx.isPointInStroke({}, 120, 70);}); +}, "isPointInStroke in Canvas throws exception with invalid parameters."); + +ctx.lineWidth = 10; +testScenarios2 = + [ + ['TestScenario 2, Case 1', 22, 22, true], + ['TestScenario 2, Case 2', 118, 22, true], + ['TestScenario 2, Case 3', 22, 118, true], + ['TestScenario 2, Case 4', 118, 118, true], + ['TestScenario 2, Case 5', 70, 18, true], + ['TestScenario 2, Case 6', 122, 70, true], + ['TestScenario 2, Case 7', 70, 122, true], + ['TestScenario 2, Case 8', 18, 70, true], + + ['TestScenario 2, Case 9', 26, 70, false], + ['TestScenario 2, Case 10', 70, 26, false], + ['TestScenario 2, Case 11', 70, 114, false], + ['TestScenario 2, Case 12', 114, 70, false] + ]; +generate_tests(testPointInStroke, testScenarios2); + +test(function(t) { + + path = new Path2D(); + path.moveTo(10,10); + path.lineTo(110,20); + path.lineTo(10,30); + ctx.lineJoin = "bevel"; + assert_false(ctx.isPointInStroke(path,113,20)); + + ctx.miterLimit = 40.0; + ctx.lineJoin = "miter"; + assert_true(ctx.isPointInStroke(path,113,20)); + + ctx.miterLimit = 2.0; + assert_false(ctx.isPointInStroke(path,113,20)); + + path = new Path2D(); + path.moveTo(10,10); + path.lineTo(110,10); + ctx.lineCap = "butt"; + assert_false(ctx.isPointInStroke(path,112,10)); + + ctx.lineCap = "round"; + assert_true(ctx.isPointInStroke(path,112,10)); + assert_false(ctx.isPointInStroke(path,117,10)); + + ctx.lineCap = "square"; + assert_true(ctx.isPointInStroke(path,112,10)); + assert_false(ctx.isPointInStroke(path,117,10)); + + ctx.lineCap = "butt"; + ctx.setLineDash([10,10]); + assert_true(ctx.isPointInStroke(path,15,10)); + assert_false(ctx.isPointInStroke(path,25,10)); + assert_true(ctx.isPointInStroke(path,35,10)); + + ctx.lineDashOffset = 10; + assert_false(ctx.isPointInStroke(path,15,10)); + assert_true(ctx.isPointInStroke(path,25,10)); + assert_false(ctx.isPointInStroke(path,35,10)); + +}, "Test the behavior of isPointInStroke in Canvas with path object"); +</script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke.html index 4c0b842..ab62eda 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-isPointInStroke.html
@@ -1,8 +1,120 @@ -<!doctype html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-isPointInStroke.js"></script> +<script> +var ctx = document.createElement('canvas').getContext('2d'); +document.body.appendChild(ctx.canvas); +ctx.strokeStyle = '#0ff'; + +// Create new path. +ctx.beginPath(); +ctx.rect(20,20,100,100); + +function testPointInStroke(x, y, isPointInStroke) { + if(isPointInStroke) + assert_true(ctx.isPointInStroke(x, y)); + else + assert_false(ctx.isPointInStroke(x, y)); +} + +testScenarios1 = + [ + ['TestScenario 1, Case 1', 20, 20, true], + ['TestScenario 1, Case 2', 120, 20, true], + ['TestScenario 1, Case 3', 20, 120, true], + ['TestScenario 1, Case 4', 120, 120, true], + ['TestScenario 1, Case 5', 70, 20, true], + ['TestScenario 1, Case 6', 20, 70, true], + ['TestScenario 1, Case 7', 120, 70, true], + ['TestScenario 1, Case 8', 70, 120, true], + + ['TestScenario 1, Case 9', 22, 22, false], + ['TestScenario 1, Case 10', 118, 22, false], + ['TestScenario 1, Case 11', 22, 118, false], + ['TestScenario 1, Case 12', 118, 118, false], + ['TestScenario 1, Case 13', 70, 18, false], + ['TestScenario 1, Case 14', 122, 70, false], + ['TestScenario 1, Case 15', 70, 122, false], + ['TestScenario 1, Case 16', 18, 70, false], + ]; + +testScenarios2 = + [ + ['TestScenario 2, Case 1', 22, 22, true], + ['TestScenario 2, Case 2', 118, 22, true], + ['TestScenario 2, Case 3', 22, 118, true], + ['TestScenario 2, Case 4', 118, 118, true], + ['TestScenario 2, Case 5', 70, 18, true], + ['TestScenario 2, Case 6', 122, 70, true], + ['TestScenario 2, Case 7', 70, 122, true], + ['TestScenario 2, Case 8', 18, 70, true], + + ['TestScenario 2, Case 9', 26, 70, false], + ['TestScenario 2, Case 10', 70, 26, false], + ['TestScenario 2, Case 11', 70, 114, false], + ['TestScenario 2, Case 12', 114, 70, false], + ]; + +generate_tests(testPointInStroke, testScenarios1); +ctx.lineWidth = 10; +generate_tests(testPointInStroke, testScenarios2); + +test(function(t) { + ctx.beginPath(); + ctx.moveTo(10,10); + ctx.lineTo(110,20); + ctx.lineTo(10,30); + ctx.lineJoin = "bevel"; + assert_false(ctx.isPointInStroke(113,20)); + + ctx.miterLimit = 40.0; + ctx.lineJoin = "miter"; + assert_true(ctx.isPointInStroke(113,20)); + + ctx.miterLimit = 2.0; + assert_false(ctx.isPointInStroke(113,20)); + + ctx.beginPath(); + ctx.moveTo(10,10); + ctx.lineTo(110,10); + ctx.lineCap = "butt"; + assert_false(ctx.isPointInStroke(112,10)); + + ctx.lineCap = "round"; + assert_true(ctx.isPointInStroke(112,10)); + assert_false(ctx.isPointInStroke(117,10)); + + ctx.lineCap = "square"; + assert_true(ctx.isPointInStroke(112,10)); + assert_false(ctx.isPointInStroke(117,10)); + + ctx.lineCap = "butt"; + ctx.setLineDash([10,10]); + assert_true(ctx.isPointInStroke(15,10)); + assert_false(ctx.isPointInStroke(25,10)); + assert_true(ctx.isPointInStroke(35,10)); + + ctx.lineDashOffset = 10; + assert_false(ctx.isPointInStroke(15,10)); + assert_true(ctx.isPointInStroke(25,10)); + assert_false(ctx.isPointInStroke(35,10)); + + ctx.save(); + ctx.scale(Number.MAX_VALUE, Number.MAX_VALUE); + ctx.beginPath(); + ctx.moveTo(-10, -10); + ctx.lineTo(10, 10); + assert_true(ctx.isPointInStroke(0, 0)); + ctx.restore(); + + ctx.save(); + ctx.scale(0, 0); + ctx.beginPath(); + ctx.moveTo(-10, -10); + ctx.lineTo(10, 10); + assert_false(ctx.isPointInStroke(0, 0)); + ctx.restore(); +}, "Test the behavior of isPointInStroke in Canvas"); + +</script> </body> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions-expected.txt deleted file mode 100644 index bd110c6..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions-expected.txt +++ /dev/null
@@ -1,36 +0,0 @@ -Tests that using reasonably large values for canvas.height and canvas.height don't cause a crash" - -PASS height == 1000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS height == 10000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS height == 32000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS width == 1000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS width == 10000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS width == 32000 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS Actual: 255 Expected: 255 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions.html index 08f38a5b..51cd946 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-dimensions.html
@@ -1,66 +1,34 @@ -<!DOCTYPE html> -<title>Canvas test: test large width/height values</title> -<script src="../../resources/js-test.js"></script> -<body> -<p>Tests that using reasonably large values for canvas.height and canvas.height don't cause a crash"</p> -<pre id="console"></pre> -<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> +<canvas id='c' width='100' height='50'></canvas> <script> -var canvas = document.getElementById("c"); -var x, y, w=1, h=1; +// Tests that using reasonably large values for canvas.height and canvas.height do not cause a crash +var canvas = document.getElementById('c'); +var x, y, w = 1, h = 1; -testHeight(canvas, 1000); -testHeight(canvas, 10000); -testHeight(canvas, 32000); - -testWidth(canvas, 1000); -testWidth(canvas, 10000); -testWidth(canvas, 32000); - -function testHeight(canvas, height) { - canvas.width = 50; - canvas.height = height; - var ctx = canvas.getContext("2d"); - ctx.fillStyle = "rgba(255, 255, 255, 1)"; - var msg = "height == "+height; - if (canvas.height == height) - testPassed(msg); - else - testFailed(msg); - x = canvas.width-2; - y = canvas.height-2; - ctx.fillRect(x,y,w,h); - var data = ctx.getImageData(x,y,w,h); - for (var x = 0; x < 4; x++) { - var msg = "Actual: " + data.data[x] + " Expected: 255"; - if (data.data[x] == 255) - testPassed(msg); - else - testFailed(msg); - } +function testLargeDimension(size, isWidth) { + canvas.width = (isWidth ? size : 50); + canvas.height = (isWidth ? 50 : size); + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'rgba(255, 255, 255, 1)'; + assert_equals((isWidth ? canvas.width : canvas.height), size); + x = canvas.width - 2; + y = canvas.height - 2; + ctx.fillRect(x, y, w, h); + var data = ctx.getImageData(x, y, w, h).data; + for (var i = 0; i < 4; i++) + assert_equals(data[i], 255); } -function testWidth(canvas, width) { - canvas.height = 50; - canvas.width = width; - var ctx = canvas.getContext("2d"); - ctx.fillStyle = "rgba(255, 255, 255, 1)"; - var msg = "width == "+width; - if (canvas.width == width) - testPassed(msg); - else - testFailed(msg); - x = canvas.width-2; - y = canvas.height-2; - ctx.fillRect(x,y,w,h); - var data = ctx.getImageData(x,y,w,h); - for (var x = 0; x < 4; x++) { - var msg = "Actual: " + data.data[x] + " Expected: 255"; - if (data.data[x] == 255) - testPassed(msg); - else - testFailed(msg); - } -} +testScenarios = [['Test Width = 1000', 1000, true], + ['Test Width = 10000', 10000, true], + ['Test Width = 32000', 32000, true], + + ['Test Height = 1000', 1000, false], + ['Test Height = 10000', 10000, false], + ['Test Height = 32000', 32000, false]]; + +generate_tests(testLargeDimension, testScenarios); + </script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills-expected.txt deleted file mode 100644 index 070bba2..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills-expected.txt +++ /dev/null
@@ -1,38 +0,0 @@ -Tests that using the different composite modes to fill large rects doesn't crash and works as expected. -PASS Fill Size 10000, source-over: #0000FF -PASS Fill Size 10000, source-in: #0000FF -PASS Fill Size 10000, source-out: #000000 -PASS Fill Size 10000, source-atop: #0000FF -PASS Fill Size 10000, destination-over: #00FF00 -PASS Fill Size 10000, destination-in: #00FF00 -PASS Fill Size 10000, destination-out: #000000 -PASS Fill Size 10000, destination-atop: #00FF00 -PASS Fill Size 10000, lighter: #00FFFF -PASS Fill Size 10000, copy: #0000FF -PASS Fill Size 10000, xor: #000000 -PASS Fill Size 50000, source-over: #0000FF -PASS Fill Size 50000, source-in: #0000FF -PASS Fill Size 50000, source-out: #000000 -PASS Fill Size 50000, source-atop: #0000FF -PASS Fill Size 50000, destination-over: #00FF00 -PASS Fill Size 50000, destination-in: #00FF00 -PASS Fill Size 50000, destination-out: #000000 -PASS Fill Size 50000, destination-atop: #00FF00 -PASS Fill Size 50000, lighter: #00FFFF -PASS Fill Size 50000, copy: #0000FF -PASS Fill Size 50000, xor: #000000 -PASS Fill Size 100000, source-over: #0000FF -PASS Fill Size 100000, source-in: #0000FF -PASS Fill Size 100000, source-out: #000000 -PASS Fill Size 100000, source-atop: #0000FF -PASS Fill Size 100000, destination-over: #00FF00 -PASS Fill Size 100000, destination-in: #00FF00 -PASS Fill Size 100000, destination-out: #000000 -PASS Fill Size 100000, destination-atop: #00FF00 -PASS Fill Size 100000, lighter: #00FFFF -PASS Fill Size 100000, copy: #0000FF -PASS Fill Size 100000, xor: #000000 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills.html index dd4c03ee..5b81aef 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-fills.html
@@ -1,11 +1,11 @@ -<!DOCTYPE html> - -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <pre id="console"></pre> -<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> +<canvas id="c" width="100" height="50"></canvas> <script> +// Tests that using the different composite modes to fill large rects doesn't crash and works as expected. var canvas = document.getElementById("c"); var ctx = canvas.getContext("2d"); @@ -15,57 +15,38 @@ ctx.fillRect(0, 0, canvas.width, canvas.height); } -var testData = [ - {compositeMode: 'source-over', expected: [0, 0, 255]}, - {compositeMode: 'source-in', expected: [0, 0, 255]}, - {compositeMode: 'source-out', expected: [0, 0, 0]}, - {compositeMode: 'source-atop', expected: [0, 0, 255]}, - {compositeMode: 'destination-over', expected: [0, 255, 0]}, - {compositeMode: 'destination-in', expected: [0, 255, 0]}, - {compositeMode: 'destination-out', expected: [0, 0, 0]}, - {compositeMode: 'destination-atop', expected: [0, 255, 0]}, - {compositeMode: 'lighter', expected: [0, 255, 255]}, - {compositeMode: 'copy', expected: [0, 0, 255]}, - {compositeMode: 'xor', expected: [0, 0, 0]}, +var testScenarios = [ + ['Test source-over', 'source-over', [0, 0, 255]], + ['Test source-in', 'source-in', [0, 0, 255]], + ['Test source-out', 'source-out', [0, 0, 0]], + ['Test source-atop', 'source-atop', [0, 0, 255]], + ['Test destination-over', 'destination-over', [0, 255, 0]], + ['Test destiation-in', 'destination-in', [0, 255, 0]], + ['Test destination-out', 'destination-out', [0, 0, 0]], + ['Test destination-atop', 'destination-atop', [0, 255, 0]], + ['Test lighter', 'lighter', [0, 255, 255]], + ['Test copy', 'copy', [0, 0, 255]], + ['Test xor', 'xor', [0, 0, 0]] ]; -function toHexString(number) { - var hexString = number.toString(16).toUpperCase(); - if (number <= 9) - hexString = '0' + hexString; - return hexString; -} - -function doTest(dataItem, fillSize) { +var fillSize = 0; +function testLargeRect(compositeMode, expected) { clearContextToGreen(); ctx.fillStyle = "rgb(0, 0, 255)"; - ctx.globalCompositeOperation = dataItem.compositeMode; + ctx.globalCompositeOperation = compositeMode; ctx.fillRect(0, 0, fillSize, fillSize); - var data = ctx.getImageData(0, 0, canvas.width, canvas.height); - var pixelOK = true; - var pixelString = '#'; - var expectedString = '#'; - - for (var x = 0; x < 3; x++) { - pixelString = pixelString + toHexString(data.data[x]); - expectedString = expectedString + toHexString(dataItem.expected[x]); - if (data.data[x] != dataItem.expected[x]) - pixelOK = false; - } - - var testName = "Fill Size " + fillSize + ', ' + dataItem.compositeMode; - if (pixelOK) - testPassed(testName + ': ' + pixelString); - else - testFailed(testName + ': EXPECTED ' + expectedString + ', GOT ' + pixelString); + var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + var testPassed = true; + for (var i = 0; i < 3; i++) + if (data[i] != expected[i]) + testPassed = false; + assert_true(testPassed); } -debug("Tests that using the different composite modes to fill large rects doesn't crash and works as expected."); -[10000, 50000, 100000].forEach(function(fillSize) { - testData.forEach(function(dataItem) { - doTest(dataItem, fillSize) - })}); +[10000, 50000, 100000].forEach(function(fillSizeItem) { + fillSize = fillSizeItem; + generate_tests(testLargeRect, testScenarios); +}); </script> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern-expected.txt deleted file mode 100644 index 29ff342..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -Verifies createPattern using a source image that is a canvas 40k pixels wide. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imgdata[0] is 0 -FAIL imgdata[1] should be 255. Was 0. -PASS imgdata[2] is 0 -FAIL imgdata[3] should be 255. Was 0. -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern.html index 1ba4fa6a..c766406 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-large-pattern.html
@@ -1,47 +1,28 @@ -<!DOCTYPE HTML> -<html> -<body> - <script src="../../resources/js-test.js"></script> - <script type="text/javascript"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> - description("Verifies createPattern using a source image that is a canvas 40k pixels wide."); - // This test does not currently succeed because skia does not handle - // canvases more than 32k pixels wide. For now, this test serves the - // purpose of verifying that this use case does not crash the browser. - // Crasher bug: crbug.com/281504 +test(function(t) { + var canvas = document.createElement('canvas'); + canvas.width = 40000; + var context = canvas.getContext('2d'); + context.fillStyle = '#0f0'; + context.fillRect(0, 0, 1, 1); - var canvas = document.createElement('canvas'); - canvas.width = 40000; - var context = canvas.getContext('2d'); - context.fillStyle = '#0f0'; - context.fillRect(0, 0, 1, 1); + var dstCanvas = document.createElement('canvas'); + var dstContext = dstCanvas.getContext('2d'); + var pattern = dstContext.createPattern(canvas, 'repeat'); + dstContext.fillStyle = pattern; + dstContext.fillRect(0, 0, dstCanvas.width, dstCanvas.height); - var dstCanvas = document.createElement('canvas'); - var dstContext = dstCanvas.getContext('2d'); - var pattern = dstContext.createPattern(canvas, 'repeat'); - dstContext.fillStyle = pattern; - dstContext.fillRect(0, 0, dstCanvas.width, dstCanvas.height); - - var imageData = dstContext.getImageData(0, 0, 1, 1); - var imgdata = imageData.data; - shouldBe("imgdata[0]", "0"); - shouldBe("imgdata[1]", "255"); - shouldBe("imgdata[2]", "0"); - shouldBe("imgdata[3]", "255"); - - imageData = dstContext.getImageData(1, 0, 1, 1); - imgdata = imageData.data; - shouldBe("imgdata[0]", "0"); - shouldBe("imgdata[1]", "0"); - shouldBe("imgdata[2]", "0"); - shouldBe("imgdata[3]", "0"); - - imageData = dstContext.getImageData(0, 1, 1, 1); - imgdata = imageData.data; - shouldBe("imgdata[0]", "0"); - shouldBe("imgdata[1]", "0"); - shouldBe("imgdata[2]", "0"); - shouldBe("imgdata[3]", "0"); - </script> -</body> -</html> + // This test does not currently succeed because skia does not handle + // canvases more than 32k pixels wide. For now, this test serves the + // purpose of verifying that this use case does not crash the browser. + // Crasher bug: crbug.com/281504. + assert_array_equals(dstContext.getImageData(0, 0, 1, 1).data, [0, 255, 0, 255]); + + assert_array_equals(dstContext.getImageData(1, 0, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(dstContext.getImageData(0, 1, 1, 1).data, [0, 0, 0, 0]); + +}, 'Tests createPattern using a source image that is a canvas 40k pixels wide.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws-expected.txt deleted file mode 100644 index 9fc405a..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -PASS: Draw commands with big numbers cause no problems.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws.html index a5f1bc8..f69ef6a 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-largedraws.html
@@ -1,47 +1,49 @@ -<!DOCTYPE html> -<html> - <body> - <script> - if (window.testRunner) - testRunner.dumpAsText(); +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> - function newCanvasContext() { - canvas = document.createElement("canvas"); - canvas.width = 100; - canvas.height = 100; - return canvas.getContext("2d"); - } +<script> +function newCanvasContext() { + canvas = document.createElement("canvas"); + canvas.width = 100; + canvas.height = 100; + return canvas.getContext("2d"); +} - window.onload = function () { - ctx = newCanvasContext(); - ctx.fillStyle = '#0f0'; - ctx.fillRect(0, 0, 100, 50); - ctx.moveTo(10500000000, 10500000000); - ctx.lineTo(110, -10); - ctx.lineTo(-10, 60); - ctx.fill(); - ctx.getImageData(50, 25, 1, 1); +function runTest() { + ctx = newCanvasContext(); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + ctx.moveTo(10500000000, 10500000000); + ctx.lineTo(110, -10); + ctx.lineTo(-10, 60); + ctx.fill(); + ctx.getImageData(50, 25, 1, 1); - ctx = newCanvasContext(); - ctx.fillStyle = '#0f0'; - ctx.scale(4500000000, 4500000000); - ctx.moveTo(0, 0.5); - ctx.lineTo(2, 0.5); - ctx.stroke(); - ctx.getImageData(50, 25, 1, 1); + ctx = newCanvasContext(); + ctx.fillStyle = '#0f0'; + ctx.scale(4500000000, 4500000000); + ctx.moveTo(0, 0.5); + ctx.lineTo(2, 0.5); + ctx.stroke(); + ctx.getImageData(50, 25, 1, 1); - ctx = newCanvasContext(); - ctx.fillStyle = '#0f0'; - ctx.fillRect(0, 0, 100, 50); - ctx.scale(2, -4500000000); - ctx.arc(25, 50, 56, 0, 2*Math.PI, false); - ctx.fill(); - ctx.arc(105000000005, -105000000005, 105000000004, 0, 10500000000*Math.PI, false); - ctx.fill(); - ctx.getImageData(50, 25, 1, 1); - } - </script> - PASS: Draw commands with big numbers cause no problems. - </body> -</html> + ctx = newCanvasContext(); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + ctx.scale(2, -4500000000); + ctx.arc(25, 50, 56, 0, 2*Math.PI, false); + ctx.fill(); + ctx.arc(105000000005, -105000000005, 105000000004, 0, 10500000000*Math.PI, false); + ctx.fill(); + ctx.getImageData(50, 25, 1, 1); +} + +async_test(t => { + window.onload = function() { + t.step(runTest); + t.done(); + } +}, 'Draw commands with big numbers cause no problems.'); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-expected.txt deleted file mode 100644 index 358c0922..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-expected.txt +++ /dev/null
@@ -1,52 +0,0 @@ -Basic test for setLineDash, getLineDash and lineDashOffset - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.lineDashOffset is 0 -PASS lineDash[0] is 15 -PASS lineDash[1] is 10 -PASS ctx.lineDashOffset is 5 -PASS lineDash[0] is 0 -PASS lineDash[1] is 0 -PASS lineDash[0] is 5 -PASS lineDash[1] is 10 -PASS lineDash[2] is 15 -PASS lineDash[3] is 5 -PASS lineDash[4] is 10 -PASS lineDash[5] is 15 -PASS lineDash[0] is 1 -PASS lineDash[1] is 2 -PASS ctx.lineDashOffset is 5 -PASS getPixel(25,10) is [0,255,0,255] -PASS getPixel(35,10) is [0,0,0,0] -PASS getPixel(40,25) is [0,255,0,255] -PASS getPixel(40,35) is [0,0,0,0] -PASS getPixel(25,40) is [0,255,0,255] -PASS getPixel(15,40) is [0,0,0,0] -PASS getPixel(10,25) is [0,255,0,255] -PASS getPixel(10,15) is [0,0,0,0] -PASS getPixel(55,10) is [0,0,0,0] -PASS getPixel(65,10) is [0,255,0,255] -PASS getPixel(80,15) is [0,0,0,0] -PASS getPixel(80,25) is [0,255,0,255] -PASS getPixel(75,40) is [0,0,0,0] -PASS getPixel(65,40) is [0,255,0,255] -PASS getPixel(50,35) is [0,0,0,0] -PASS getPixel(50,25) is [0,255,0,255] -PASS getPixel(95,10) is [0,0,0,0] -PASS getPixel(105,10) is [0,255,0,255] -PASS getPixel(120,15) is [0,0,0,0] -PASS getPixel(120,25) is [0,255,0,255] -PASS getPixel(115,40) is [0,0,0,0] -PASS getPixel(105,40) is [0,255,0,255] -PASS getPixel(90,35) is [0,0,0,0] -PASS getPixel(90,25) is [0,255,0,255] -PASS getPixel(130,10) is [0,255,0,255] -PASS getPixel(130,15) is [0,255,0,255] -PASS getPixel(130,25) is [0,255,0,255] -PASS getPixel(130,35) is [0,255,0,255] -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence-expected.txt deleted file mode 100644 index f316f8c..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence-expected.txt +++ /dev/null
@@ -1,69 +0,0 @@ -Test that setLineDash converts input argument into a Web IDL sequence - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -* Test passing a Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Int8Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Int16Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Int32Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Uint8Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Uint16Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Uint32Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Float32Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Float64Array as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Uint8ClampedArray as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Object as input. -PASS lineDash[0] is 5 -PASS lineDash[1] is 15 -PASS lineDash[2] is 25 -* Test passing a Date as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing a RegExp as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing an Object without length as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing a Number as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing a String as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing a Boolean as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing null as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -* Test passing undefined as input. -PASS ctx.setLineDash(inputArray) threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': The 1st argument is neither an array, nor does it have indexed properties.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence.html index 061d9f4..1cbcb5f 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-input-sequence.html
@@ -1,77 +1,75 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> <link rel="help" href="http://www.w3.org/TR/2013/WD-2dcontext2-20130528/#dom-context-2d-setlinedash"> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> <script> -description("Test that setLineDash converts input argument into a Web IDL sequence"); - -var canvas = document.createElement('canvas'); -document.body.appendChild(canvas); -canvas.setAttribute('width', '700'); -canvas.setAttribute('height', '700'); -var ctx = canvas.getContext('2d'); - -var arrayValues = [5, 15, 25]; - -function createTestArray(arrayType) { - var array; - if (arrayType == Object) { - // Test a "sequence" (Object with length property). - array = {length: arrayValues.length}; - } else { - array = new arrayType(arrayValues.length); - } - - for (var i = 0; i < arrayValues.length; ++i) - array[i] = arrayValues[i] - return array; -} - -var lineDash; -var inputArray; -function checkLineDash(testArray, shouldFail) { - inputArray = testArray; - // Reset line dash. - ctx.setLineDash([]); - // Set line dash. - if (shouldFail) { - shouldThrow("ctx.setLineDash(inputArray)", "'TypeError: Failed to execute \\'setLineDash\\' on \\'CanvasRenderingContext2D\\': The 1st argument is neither an array, nor does it have indexed properties.'"); - } else { - ctx.setLineDash(inputArray); - lineDash = ctx.getLineDash(); - for (var i = 0; i < arrayValues.length; ++i) - shouldBe("lineDash[" + i + "]", "" + arrayValues[i]); +test(function(t) { + + var canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + canvas.setAttribute('width', '700'); + canvas.setAttribute('height', '700'); + var ctx = canvas.getContext('2d'); + + var arrayValues = [5, 15, 25]; + + function createTestArray(arrayType) { + var array; + if (arrayType == Object) { + // Test a "sequence" (Object with length property). + array = {length: arrayValues.length}; + } else { + array = new arrayType(arrayValues.length); + } + + for (var i = 0; i < arrayValues.length; ++i) + array[i] = arrayValues[i] + return array; } -} - -var arrayTypes = [Array, Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array, Uint8ClampedArray, Object]; - -// Success cases. -for (var i = 0; i < arrayTypes.length; ++i) { - debug("* Test passing a " + arrayTypes[i].name + " as input."); - checkLineDash(createTestArray(arrayTypes[i]), false); -} - -// Failure cases. -debug("* Test passing a Date as input."); -checkLineDash(new Date(), true); -debug("* Test passing a RegExp as input."); -checkLineDash(new RegExp(), true); -debug("* Test passing an Object without length as input."); -checkLineDash({test: 1}, true); -debug("* Test passing a Number as input."); -checkLineDash(3, true); -debug("* Test passing a String as input."); -checkLineDash("Test", true); -debug("* Test passing a Boolean as input."); -checkLineDash(true, true); -debug("* Test passing null as input."); -checkLineDash(null, true); -debug("* Test passing undefined as input."); -checkLineDash(undefined, true); + + var lineDash; + var inputArray; + function checkLineDash(testArray, shouldFail) { + inputArray = testArray; + // Reset line dash. + ctx.setLineDash([]); + // Set line dash. + if (shouldFail) { + assert_throws(null, function() {ctx.setLineDash(inputArray);}, "'TypeError: Failed to execute \\'setLineDash\\' on \\'CanvasRenderingContext2D\\': The 1st argument is neither an array, nor does it have indexed properties.'"); + } else { + ctx.setLineDash(inputArray); + lineDash = ctx.getLineDash(); + for (var i = 0; i < arrayValues.length; ++i) + assert_equals(lineDash[i], arrayValues[i]); + } + } + + var arrayTypes = [Array, Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Float32Array, Float64Array, Uint8ClampedArray, Object]; + + // Success cases. + for (var i = 0; i < arrayTypes.length; ++i) { + // Test passing a valid array time as input. + checkLineDash(createTestArray(arrayTypes[i]), false); + } + + // Failure cases. + // Test passing a Date as input. + checkLineDash(new Date(), true); + // Test passing a RegExp as input. + checkLineDash(new RegExp(), true); + // Test passing an Object without length as input. + checkLineDash({test: 1}, true); + // Test passing a Number as input. + checkLineDash(3, true); + // Test passing a String as input. + checkLineDash("Test", true); + // Test passing a Boolean as input. + checkLineDash(true, true); + // Test passing null as input. + checkLineDash(null, true); + // Test passing undefined as input. + checkLineDash(undefined, true); + +}, 'Test that setLineDash converts input argument into a Web IDL sequence'); </script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid-expected.txt deleted file mode 100644 index 1c4ff67..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid-expected.txt +++ /dev/null
@@ -1,19 +0,0 @@ -Test for invalid input of setLineDash, getLineDash and lineDashOffset - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS trySettingLineDash([1, -1]) is initialLineDash -PASS trySettingLineDash([1, Infinity]) is initialLineDash -PASS trySettingLineDash([1, -Infinity]) is initialLineDash -PASS trySettingLineDash([1, NaN]) is initialLineDash -PASS trySettingLineDash([1, 'string']) is initialLineDash -PASS trySettingLineDashWithNoArgs() threw exception TypeError: Failed to execute 'setLineDash' on 'CanvasRenderingContext2D': 1 argument required, but only 0 present.. -PASS trySettingLineDashOffset(Infinity) is initialLineDashOffset -PASS trySettingLineDashOffset(-Infinity) is initialLineDashOffset -PASS trySettingLineDashOffset(NaN) is initialLineDashOffset -PASS trySettingLineDashOffset('string') is initialLineDashOffset -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid.html index a9c0e4c..ae72a51 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash-invalid.html
@@ -1,9 +1,52 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-lineDash-invalid.js"></script> +<script> + +var canvas = document.createElement('canvas'); +document.body.appendChild(canvas); +canvas.setAttribute('width', '700'); +canvas.setAttribute('height', '700'); +var ctx = canvas.getContext('2d'); +var initialLineDash = [1.5, 2.5]; +var initialLineDashOffset = 1.5; + +function resetLineDash() { + ctx.setLineDash(initialLineDash); + ctx.lineDashOffset = initialLineDashOffset; +} + +function trySettingLineDash(value) { + resetLineDash(); + ctx.setLineDash(value); + return ctx.getLineDash(); +} + +function trySettingLineDashWithNoArgs() { + resetLineDash(); + ctx.setLineDash(); + return ctx.getLineDash(); +} + +function trySettingLineDashOffset(value) { + resetLineDash(); + ctx.lineDashOffset = value; + return ctx.lineDashOffset; +} + +test(function(t) { + assert_array_equals(trySettingLineDash([1, -1]), initialLineDash); + assert_array_equals(trySettingLineDash([1, Infinity]), initialLineDash); + assert_array_equals(trySettingLineDash([1, -Infinity]), initialLineDash); + assert_array_equals(trySettingLineDash([1, NaN]), initialLineDash); + assert_array_equals(trySettingLineDash([1, 'string']), initialLineDash); + assert_throws(null, function() {trySettingLineDashWithNoArgs();}, '"TypeError: Failed to execute \'setLineDash\' on \'CanvasRenderingContext2D\': 1 argument required, but only 0 present."'); + + assert_array_equals(trySettingLineDashOffset(Infinity), initialLineDashOffset); + assert_array_equals(trySettingLineDashOffset(-Infinity), initialLineDashOffset); + assert_array_equals(trySettingLineDashOffset(NaN), initialLineDashOffset); + assert_array_equals(trySettingLineDashOffset('string'), initialLineDashOffset); + +}, "Test for invalid input of setLineDash, getLineDash and lineDashOffset"); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash.html index a546137..fb10f98 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-lineDash.html
@@ -1,9 +1,110 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/canvas-lineDash.js"></script> +<script> +test(function(t) { + + var canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + canvas.setAttribute('width', '700'); + canvas.setAttribute('height', '700'); + var ctx = canvas.getContext('2d'); + + // Verify default values. + assert_equals(ctx.lineDashOffset, 0); + + // Set dash-style. + ctx.setLineDash([15, 10]); + ctx.lineDashOffset = 5; + ctx.strokeRect (10,10,100,100); + + // Verify dash and offset. + var lineDash; + lineDash = ctx.getLineDash(); + assert_equals(lineDash[0], 15); + assert_equals(lineDash[1], 10); + assert_equals(ctx.lineDashOffset, 5); + + // Verify setting line dash to sequence of nulls is interpreted as zeros + ctx.setLineDash([null, null]); + lineDash = ctx.getLineDash(); + assert_equals(lineDash[0], 0); + assert_equals(lineDash[1], 0); + + // Set dash style to even number + ctx.setLineDash([5, 10, 15]); + ctx.strokeRect(20, 20, 120, 120); + + // Verify dash pattern is normalized + lineDash = ctx.getLineDash(); + assert_equals(lineDash[0], 5); + assert_equals(lineDash[1], 10); + assert_equals(lineDash[2], 15); + assert_equals(lineDash[3], 5); + assert_equals(lineDash[4], 10); + assert_equals(lineDash[5], 15); + + // Verify that conversion from string works + ctx.setLineDash(["1", 2]); + lineDash = ctx.getLineDash(); + assert_equals(lineDash[0], 1); + assert_equals(lineDash[1], 2); + + // Verify that line dash offset persists after + // clearRect (which causes a save/restore of the context + // state to the stack). + ctx.clearRect(0, 0, 700, 700); + assert_equals(ctx.lineDashOffset, 5); + + // Verify dash rendering + ctx.setLineDash([20, 10]); + ctx.lineDashOffset = 0; + ctx.lineWidth = 4; // To make the test immune to plaform anti-aliasing discrepancies + ctx.strokeStyle = '#00FF00'; + ctx.strokeRect(10.5, 10.5, 30, 30); + + assert_array_equals(ctx.getImageData(25, 10, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(35, 10, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(40, 25, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(40, 35, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(25, 40, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(15, 40, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(10, 25, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(10, 15, 1, 1).data, [0, 0, 0, 0]); + + // Verify that lineDashOffset works as expected + ctx.lineDashOffset = 20; + ctx.strokeRect(50.5, 10.5, 30, 30); + assert_array_equals(ctx.getImageData(55, 10, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(65, 10, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(80, 15, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(80, 25, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(75, 40, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(65, 40, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(50, 35, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(50, 25, 1, 1).data, [0, 255, 0, 255]); + + // Verify negative lineDashOffset + ctx.lineDashOffset = -10; + ctx.strokeRect(90.5, 10.5, 30, 30); + assert_array_equals(ctx.getImageData(95, 10, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(105, 10, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(120, 15, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(120, 25, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(115, 40, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(105, 40, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(90, 35, 1, 1).data, [0, 0, 0, 0]); + assert_array_equals(ctx.getImageData(90, 25, 1, 1).data, [0, 255, 0, 255]); + + // Verify that all zero dash sequence results in no dashing + ctx.setLineDash([0, 0]); + ctx.lineDashOffset = 0; + ctx.strokeRect(130.5, 10.5, 30, 30); + assert_array_equals(ctx.getImageData(130, 10, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(130, 15, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(130, 25, 1, 1).data, [0, 255, 0, 255]); + assert_array_equals(ctx.getImageData(130, 35, 1, 1).data, [0, 255, 0, 255]); + +}, "Basic test for setLineDash, getLineDash and lineDashOffset"); +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInPath-winding.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInPath-winding.js deleted file mode 100644 index 3d788aa..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInPath-winding.js +++ /dev/null
@@ -1,103 +0,0 @@ -description("Series of tests to ensure correct results of the winding rule in isPointInPath."); - -var tmpimg = document.createElement('canvas'); -tmpimg.width = 200; -tmpimg.height = 200; -ctx = tmpimg.getContext('2d'); - -// Execute test. -function prepareTestScenario() { - debug('Testing default isPointInPath'); - ctx.beginPath(); - ctx.rect(0, 0, 100, 100); - ctx.rect(25, 25, 50, 50); - shouldBeTrue("ctx.isPointInPath(50, 50)"); - shouldBeFalse("ctx.isPointInPath(NaN, 50)"); - shouldBeFalse("ctx.isPointInPath(50, NaN)"); - debug(''); - - debug('Testing nonzero isPointInPath'); - ctx.beginPath(); - ctx.rect(0, 0, 100, 100); - ctx.rect(25, 25, 50, 50); - shouldBeTrue("ctx.isPointInPath(50, 50, 'nonzero')"); - debug(''); - - debug('Testing evenodd isPointInPath'); - ctx.beginPath(); - ctx.rect(0, 0, 100, 100); - ctx.rect(25, 25, 50, 50); - shouldBeFalse("ctx.isPointInPath(50, 50, 'evenodd')"); - debug(''); - - // reset path in context - ctx.beginPath(); - - debug('Testing default isPointInPath with Path object'); - path = new Path2D(); - path.rect(0, 0, 100, 100); - path.rect(25, 25, 50, 50); - shouldBeTrue("ctx.isPointInPath(path, 50, 50)"); - shouldBeTrue("ctx.isPointInPath(path, 50, 50, undefined)"); - shouldBeFalse("ctx.isPointInPath(path, NaN, 50)"); - shouldBeFalse("ctx.isPointInPath(path, 50, NaN)"); - debug(''); - - debug('Testing nonzero isPointInPath with Path object'); - path = new Path2D(); - path.rect(0, 0, 100, 100); - path.rect(25, 25, 50, 50); - shouldBeTrue("ctx.isPointInPath(path, 50, 50, 'nonzero')"); - debug(''); - - debug('Testing evenodd isPointInPath with Path object'); - path = new Path2D(); - path.rect(0, 0, 100, 100); - path.rect(25, 25, 50, 50); - shouldBeFalse("ctx.isPointInPath(path, 50, 50, 'evenodd')"); - debug(''); - - debug('Testing invalid enumeration isPointInPath (w/ and w/o Path object'); - shouldThrow("ctx.isPointInPath(path, 50, 50, 'gazonk')"); - shouldThrow("ctx.isPointInPath(50, 50, 'gazonk')"); - debug(''); - - debug('Testing invalid type isPointInPath with Path object'); - shouldThrow("ctx.isPointInPath(null, 50, 50)"); - shouldThrow("ctx.isPointInPath(null, 50, 50, 'nonzero')"); - shouldThrow("ctx.isPointInPath(null, 50, 50, 'evenodd')"); - shouldThrow("ctx.isPointInPath(null, 50, 50, null)"); - shouldThrow("ctx.isPointInPath(path, 50, 50, null)"); - shouldThrow("ctx.isPointInPath(undefined, 50, 50)"); - shouldThrow("ctx.isPointInPath(undefined, 50, 50, 'nonzero')"); - shouldThrow("ctx.isPointInPath(undefined, 50, 50, 'evenodd')"); - shouldThrow("ctx.isPointInPath(undefined, 50, 50, undefined)"); - shouldThrow("ctx.isPointInPath([], 50, 50)"); - shouldThrow("ctx.isPointInPath([], 50, 50, 'nonzero')"); - shouldThrow("ctx.isPointInPath([], 50, 50, 'evenodd')"); - shouldThrow("ctx.isPointInPath({}, 50, 50)"); - shouldThrow("ctx.isPointInPath({}, 50, 50, 'nonzero')"); - shouldThrow("ctx.isPointInPath({}, 50, 50, 'evenodd')"); - debug(''); - - debug("Testing extremely large scale") - ctx.save(); - ctx.scale(Number.MAX_VALUE, Number.MAX_VALUE); - ctx.beginPath(); - ctx.rect(-10, -10, 20, 20); - shouldBeTrue("ctx.isPointInPath(0, 0, 'nonzero')"); - shouldBeTrue("ctx.isPointInPath(0, 0, 'evenodd')"); - ctx.restore(); - - debug("Check with non-invertible ctm.") - ctx.save(); - ctx.scale(0, 0); - ctx.beginPath(); - ctx.rect(-10, -10, 20, 20); - shouldBeFalse("ctx.isPointInPath(0, 0, 'nonzero')"); - shouldBeFalse("ctx.isPointInPath(0, 0, 'evenodd')"); - ctx.restore(); -} - -// Run test and allow variation of results. -prepareTestScenario();
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke-with-path.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke-with-path.js deleted file mode 100644 index 383b00d0..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke-with-path.js +++ /dev/null
@@ -1,108 +0,0 @@ -description("Test the behavior of isPointInStroke in Canvas with path object"); -var ctx = document.createElement('canvas').getContext('2d'); - -document.body.appendChild(ctx.canvas); - -ctx.strokeStyle = '#0ff'; - -// Create new path. -var path = new Path2D(); -path.rect(20,20,100,100); - -debug("Initial behavior: lineWidth = 1.0") -shouldBeTrue("ctx.isPointInStroke(path,20,20)"); -shouldBeTrue("ctx.isPointInStroke(path,120,20)"); -shouldBeTrue("ctx.isPointInStroke(path,20,120)"); -shouldBeTrue("ctx.isPointInStroke(path,120,120)"); -shouldBeTrue("ctx.isPointInStroke(path,70,20)"); -shouldBeTrue("ctx.isPointInStroke(path,20,70)"); -shouldBeTrue("ctx.isPointInStroke(path,120,70)"); -shouldBeTrue("ctx.isPointInStroke(path,70,120)"); -shouldBeFalse("ctx.isPointInStroke(path,22,22)"); -shouldBeFalse("ctx.isPointInStroke(path,118,22)"); -shouldBeFalse("ctx.isPointInStroke(path,22,118)"); -shouldBeFalse("ctx.isPointInStroke(path,118,118)"); -shouldBeFalse("ctx.isPointInStroke(path,70,18)"); -shouldBeFalse("ctx.isPointInStroke(path,122,70)"); -shouldBeFalse("ctx.isPointInStroke(path,70,122)"); -shouldBeFalse("ctx.isPointInStroke(path,18,70)"); -shouldBeFalse("ctx.isPointInStroke(path,NaN,122)"); -shouldBeFalse("ctx.isPointInStroke(path,18,NaN)"); -debug(""); - -debug("Check invalid type"); -shouldThrow("ctx.isPointInStroke(null,70,20)"); -shouldThrow("ctx.isPointInStroke(undefined,70,20)"); -shouldThrow("ctx.isPointInStroke([],20,70)"); -shouldThrow("ctx.isPointInStroke({},120,70)"); -debug(""); - -debug("Set lineWidth = 10.0"); -ctx.lineWidth = 10; -shouldBeTrue("ctx.isPointInStroke(path,22,22)"); -shouldBeTrue("ctx.isPointInStroke(path,118,22)"); -shouldBeTrue("ctx.isPointInStroke(path,22,118)"); -shouldBeTrue("ctx.isPointInStroke(path,118,118)"); -shouldBeTrue("ctx.isPointInStroke(path,70,18)"); -shouldBeTrue("ctx.isPointInStroke(path,122,70)"); -shouldBeTrue("ctx.isPointInStroke(path,70,122)"); -shouldBeTrue("ctx.isPointInStroke(path,18,70)"); -shouldBeFalse("ctx.isPointInStroke(path,26,70)"); -shouldBeFalse("ctx.isPointInStroke(path,70,26)"); -shouldBeFalse("ctx.isPointInStroke(path,70,114)"); -shouldBeFalse("ctx.isPointInStroke(path,114,70)"); -debug(""); - -debug("Check lineJoin = 'bevel'"); -path = new Path2D(); -path.moveTo(10,10); -path.lineTo(110,20); -path.lineTo(10,30); -ctx.lineJoin = "bevel"; -shouldBeFalse("ctx.isPointInStroke(path,113,20)"); -debug(""); - -debug("Check lineJoin = 'miter'"); -ctx.miterLimit = 40.0; -ctx.lineJoin = "miter"; -shouldBeTrue("ctx.isPointInStroke(path,113,20)"); -debug(""); - -debug("Check miterLimit = 2.0"); -ctx.miterLimit = 2.0; -shouldBeFalse("ctx.isPointInStroke(path,113,20)"); -debug(""); - -debug("Check lineCap = 'butt'"); -path = new Path2D(); -path.moveTo(10,10); -path.lineTo(110,10); -ctx.lineCap = "butt"; -shouldBeFalse("ctx.isPointInStroke(path,112,10)"); -debug(""); - -debug("Check lineCap = 'round'"); -ctx.lineCap = "round"; -shouldBeTrue("ctx.isPointInStroke(path,112,10)"); -shouldBeFalse("ctx.isPointInStroke(path,117,10)"); -debug(""); - -debug("Check lineCap = 'square'"); -ctx.lineCap = "square"; -shouldBeTrue("ctx.isPointInStroke(path,112,10)"); -shouldBeFalse("ctx.isPointInStroke(path,117,10)"); -debug(""); - -debug("Check setLineDash([10,10])"); -ctx.lineCap = "butt"; -ctx.setLineDash([10,10]); -shouldBeTrue("ctx.isPointInStroke(path,15,10)"); -shouldBeFalse("ctx.isPointInStroke(path,25,10)"); -shouldBeTrue("ctx.isPointInStroke(path,35,10)"); -debug(""); - -debug("Check dashOffset = 10"); -ctx.lineDashOffset = 10; -shouldBeFalse("ctx.isPointInStroke(path,15,10)"); -shouldBeTrue("ctx.isPointInStroke(path,25,10)"); -shouldBeFalse("ctx.isPointInStroke(path,35,10)");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke.js deleted file mode 100644 index 2a75b3ad..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-isPointInStroke.js +++ /dev/null
@@ -1,117 +0,0 @@ -description("Test the behavior of isPointInStroke in Canvas"); -var ctx = document.createElement('canvas').getContext('2d'); - -document.body.appendChild(ctx.canvas); - -ctx.strokeStyle = '#0ff'; - -// Create new path. -ctx.beginPath(); -ctx.rect(20,20,100,100); - -debug("Initial behavior: lineWith = 1.0") -shouldBeTrue("ctx.isPointInStroke(20,20)"); -shouldBeTrue("ctx.isPointInStroke(120,20)"); -shouldBeTrue("ctx.isPointInStroke(20,120)"); -shouldBeTrue("ctx.isPointInStroke(120,120)"); -shouldBeTrue("ctx.isPointInStroke(70,20)"); -shouldBeTrue("ctx.isPointInStroke(20,70)"); -shouldBeTrue("ctx.isPointInStroke(120,70)"); -shouldBeTrue("ctx.isPointInStroke(70,120)"); -shouldBeFalse("ctx.isPointInStroke(22,22)"); -shouldBeFalse("ctx.isPointInStroke(118,22)"); -shouldBeFalse("ctx.isPointInStroke(22,118)"); -shouldBeFalse("ctx.isPointInStroke(118,118)"); -shouldBeFalse("ctx.isPointInStroke(70,18)"); -shouldBeFalse("ctx.isPointInStroke(122,70)"); -shouldBeFalse("ctx.isPointInStroke(70,122)"); -shouldBeFalse("ctx.isPointInStroke(18,70)"); -debug(""); - -debug("Set lineWith = 10.0"); -ctx.lineWidth = 10; -shouldBeTrue("ctx.isPointInStroke(22,22)"); -shouldBeTrue("ctx.isPointInStroke(118,22)"); -shouldBeTrue("ctx.isPointInStroke(22,118)"); -shouldBeTrue("ctx.isPointInStroke(118,118)"); -shouldBeTrue("ctx.isPointInStroke(70,18)"); -shouldBeTrue("ctx.isPointInStroke(122,70)"); -shouldBeTrue("ctx.isPointInStroke(70,122)"); -shouldBeTrue("ctx.isPointInStroke(18,70)"); -shouldBeFalse("ctx.isPointInStroke(26,70)"); -shouldBeFalse("ctx.isPointInStroke(70,26)"); -shouldBeFalse("ctx.isPointInStroke(70,114)"); -shouldBeFalse("ctx.isPointInStroke(114,70)"); -debug(""); - -debug("Check lineJoin = 'bevel'"); -ctx.beginPath(); -ctx.moveTo(10,10); -ctx.lineTo(110,20); -ctx.lineTo(10,30); -ctx.lineJoin = "bevel"; -shouldBeFalse("ctx.isPointInStroke(113,20)"); -debug(""); - -debug("Check lineJoin = 'miter'"); -ctx.miterLimit = 40.0; -ctx.lineJoin = "miter"; -shouldBeTrue("ctx.isPointInStroke(113,20)"); -debug(""); - -debug("Check miterLimit = 2.0"); -ctx.miterLimit = 2.0; -shouldBeFalse("ctx.isPointInStroke(113,20)"); -debug(""); - -debug("Check lineCap = 'butt'"); -ctx.beginPath(); -ctx.moveTo(10,10); -ctx.lineTo(110,10); -ctx.lineCap = "butt"; -shouldBeFalse("ctx.isPointInStroke(112,10)"); -debug(""); - -debug("Check lineCap = 'round'"); -ctx.lineCap = "round"; -shouldBeTrue("ctx.isPointInStroke(112,10)"); -shouldBeFalse("ctx.isPointInStroke(117,10)"); -debug(""); - -debug("Check lineCap = 'square'"); -ctx.lineCap = "square"; -shouldBeTrue("ctx.isPointInStroke(112,10)"); -shouldBeFalse("ctx.isPointInStroke(117,10)"); -debug(""); - -debug("Check setLineDash([10,10])"); -ctx.lineCap = "butt"; -ctx.setLineDash([10,10]); -shouldBeTrue("ctx.isPointInStroke(15,10)"); -shouldBeFalse("ctx.isPointInStroke(25,10)"); -shouldBeTrue("ctx.isPointInStroke(35,10)"); -debug(""); - -debug("Check dashOffset = 10"); -ctx.lineDashOffset = 10; -shouldBeFalse("ctx.isPointInStroke(15,10)"); -shouldBeTrue("ctx.isPointInStroke(25,10)"); -shouldBeFalse("ctx.isPointInStroke(35,10)"); - -debug("Check extremely large scale") -ctx.save(); -ctx.scale(Number.MAX_VALUE, Number.MAX_VALUE); -ctx.beginPath(); -ctx.moveTo(-10, -10); -ctx.lineTo(10, 10); -shouldBeTrue("ctx.isPointInStroke(0, 0)"); -ctx.restore(); - -debug("Check with non-invertible ctm.") -ctx.save(); -ctx.scale(0, 0); -ctx.beginPath(); -ctx.moveTo(-10, -10); -ctx.lineTo(10, 10); -shouldBeFalse("ctx.isPointInStroke(0, 0)"); -ctx.restore();
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash-invalid.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash-invalid.js deleted file mode 100644 index 35f73df..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash-invalid.js +++ /dev/null
@@ -1,44 +0,0 @@ -description("Test for invalid input of setLineDash, getLineDash and lineDashOffset"); - -var canvas = document.createElement('canvas'); -document.body.appendChild(canvas); -canvas.setAttribute('width', '700'); -canvas.setAttribute('height', '700'); -var ctx = canvas.getContext('2d'); -var initialLineDash = [1.5, 2.5]; -var initialLineDashOffset = 1.5; - -function resetLineDash() { - ctx.setLineDash(initialLineDash); - ctx.lineDashOffset = initialLineDashOffset; -} - -function trySettingLineDash(value) { - resetLineDash(); - ctx.setLineDash(value); - return ctx.getLineDash(); -} - -function trySettingLineDashWithNoArgs() { - resetLineDash(); - ctx.setLineDash(); - return ctx.getLineDash(); -} - -function trySettingLineDashOffset(value) { - resetLineDash(); - ctx.lineDashOffset = value; - return ctx.lineDashOffset; -} - -shouldBe("trySettingLineDash([1, -1])", "initialLineDash"); -shouldBe("trySettingLineDash([1, Infinity])", "initialLineDash"); -shouldBe("trySettingLineDash([1, -Infinity])", "initialLineDash"); -shouldBe("trySettingLineDash([1, NaN])", "initialLineDash"); -shouldBe("trySettingLineDash([1, 'string'])", "initialLineDash"); -shouldThrow("trySettingLineDashWithNoArgs()", '"TypeError: Failed to execute \'setLineDash\' on \'CanvasRenderingContext2D\': 1 argument required, but only 0 present."'); - -shouldBe("trySettingLineDashOffset(Infinity)", "initialLineDashOffset"); -shouldBe("trySettingLineDashOffset(-Infinity)", "initialLineDashOffset"); -shouldBe("trySettingLineDashOffset(NaN)", "initialLineDashOffset"); -shouldBe("trySettingLineDashOffset('string')", "initialLineDashOffset");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash.js deleted file mode 100644 index 8c3c8002..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/canvas-lineDash.js +++ /dev/null
@@ -1,120 +0,0 @@ -description("Basic test for setLineDash, getLineDash and lineDashOffset"); - -var canvas = document.createElement('canvas'); -document.body.appendChild(canvas); -canvas.setAttribute('width', '700'); -canvas.setAttribute('height', '700'); -var ctx = canvas.getContext('2d'); - -function dataToArray(data) { - var result = new Array(data.length) - for (var i = 0; i < data.length; i++) - result[i] = data[i]; - return result; -} - -function getPixel(x, y) { - var data = ctx.getImageData(x,y,1,1); - if (!data) // getImageData failed, which should never happen - return [-1,-1,-1,-1]; - return dataToArray(data.data); -} - -function pixelShouldBe(x, y, colour) { - shouldBe("getPixel(" + [x, y] +")", "["+colour+"]"); -} - -// Verify default values. -shouldBe('ctx.lineDashOffset', '0'); - -// Set dash-style. -ctx.setLineDash([15, 10]); -ctx.lineDashOffset = 5; -ctx.strokeRect (10,10,100,100); - -// Verify dash and offset. -var lineDash; -lineDash = ctx.getLineDash(); -shouldBe('lineDash[0]', '15'); -shouldBe('lineDash[1]', '10'); -shouldBe('ctx.lineDashOffset', '5'); - -// Verify setting line dash to sequence of nulls is interpreted as zeros -ctx.setLineDash([null, null]); -lineDash = ctx.getLineDash(); -shouldBe('lineDash[0]', '0'); -shouldBe('lineDash[1]', '0'); - -// Set dash style to even number -ctx.setLineDash([5, 10, 15]); -ctx.strokeRect(20, 20, 120, 120); - -// Verify dash pattern is normalized -lineDash = ctx.getLineDash(); -shouldBe('lineDash[0]', '5'); -shouldBe('lineDash[1]', '10'); -shouldBe('lineDash[2]', '15'); -shouldBe('lineDash[3]', '5'); -shouldBe('lineDash[4]', '10'); -shouldBe('lineDash[5]', '15'); - -// Verify that conversion from string works -ctx.setLineDash(["1", 2]); -lineDash = ctx.getLineDash(); -shouldBe('lineDash[0]', '1'); -shouldBe('lineDash[1]', '2'); - -// Verify that line dash offset persists after -// clearRect (which causes a save/restore of the context -// state to the stack). -ctx.clearRect(0, 0, 700, 700); -shouldBe('ctx.lineDashOffset', '5'); - -// Verify dash rendering -ctx.setLineDash([20, 10]); -ctx.lineDashOffset = 0; -ctx.lineWidth = 4; // To make the test immune to plaform anti-aliasing discrepancies -ctx.strokeStyle = '#00FF00'; -ctx.strokeRect(10.5, 10.5, 30, 30); - -pixelShouldBe(25, 10, [0, 255, 0, 255]); -pixelShouldBe(35, 10, [0, 0, 0, 0]); -pixelShouldBe(40, 25, [0, 255, 0, 255]); -pixelShouldBe(40, 35, [0, 0, 0, 0]); -pixelShouldBe(25, 40, [0, 255, 0, 255]); -pixelShouldBe(15, 40, [0, 0, 0, 0]); -pixelShouldBe(10, 25, [0, 255, 0, 255]); -pixelShouldBe(10, 15, [0, 0, 0, 0]); - -// Verify that lineDashOffset works as expected -ctx.lineDashOffset = 20; -ctx.strokeRect(50.5, 10.5, 30, 30); -pixelShouldBe(55, 10, [0, 0, 0, 0]); -pixelShouldBe(65, 10, [0, 255, 0, 255]); -pixelShouldBe(80, 15, [0, 0, 0, 0]); -pixelShouldBe(80, 25, [0, 255, 0, 255]); -pixelShouldBe(75, 40, [0, 0, 0, 0]); -pixelShouldBe(65, 40, [0, 255, 0, 255]); -pixelShouldBe(50, 35, [0, 0, 0, 0]); -pixelShouldBe(50, 25, [0, 255, 0, 255]); - -// Verify negative lineDashOffset -ctx.lineDashOffset = -10; -ctx.strokeRect(90.5, 10.5, 30, 30); -pixelShouldBe(95, 10, [0, 0, 0, 0]); -pixelShouldBe(105, 10, [0, 255, 0, 255]); -pixelShouldBe(120, 15, [0, 0, 0, 0]); -pixelShouldBe(120, 25, [0, 255, 0, 255]); -pixelShouldBe(115, 40, [0, 0, 0, 0]); -pixelShouldBe(105, 40, [0, 255, 0, 255]); -pixelShouldBe(90, 35, [0, 0, 0, 0]); -pixelShouldBe(90, 25, [0, 255, 0, 255]); - -// Verify that all zero dash sequence results in no dashing -ctx.setLineDash([0, 0]); -ctx.lineDashOffset = 0; -ctx.strokeRect(130.5, 10.5, 30, 30); -pixelShouldBe(130, 10, [0, 255, 0, 255]); -pixelShouldBe(130, 15, [0, 255, 0, 255]); -pixelShouldBe(130, 25, [0, 255, 0, 255]); -pixelShouldBe(130, 35, [0, 255, 0, 255]);
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html index bf2d937..9e4d1b3 100644 --- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/multi-pointer-event-in-slop-region.html
@@ -49,18 +49,18 @@ [{source: "touch", actions: [ { name: "pointerDown", x: x, y: y }, - { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerMove", x: x, y: y + 1 }, { name: "pause" }, { name: "pause" }, { name: "pause" }, - { name: "pointerMove", x: x, y: y + 6 }, + { name: "pointerMove", x: x, y: y + 2 }, { name: "pointerUp" }]}, {source: "touch", actions: [ { name: "pause" }, { name: "pause" }, { name: "pointerDown", x: x, y: y }, - { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerMove", x: x, y: y + 1 }, { name: "pointerUp"}]}]; chrome.gpuBenchmarking.pointerActionSequence(pointerActions, callbackValidMoveCount); }
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html new file mode 100644 index 0000000..e4f8298d --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html
@@ -0,0 +1,69 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<style type="text/css"> +#box { + width: 600px; + height: 600px; + touch-action: none; +} +</style> +<div id="box" ></div> + +<script type="text/javascript"> + +var touchMoveCount = 0; +var pointerMoveCount = 0; +var box = document.getElementById("box"); +var targetRect = box.getBoundingClientRect(); +var offset = 50; +var x = targetRect.left + offset; +var y = targetRect.top + offset; + +function touchstartHandler(event) { + event.preventDefault(); +} + +function validTouchMoveResult(event) { + touchMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + }); +} + +function validPointerMoveResult(event) { + pointerMoveCount++; + testTouchMove.step(function () { + assert_equals(event.target.id, "box"); + assert_equals(event.pointerType, "touch"); + }); +} + +function callbackValidMoveCount() { + testTouchMove.step(function () { + assert_equals(touchMoveCount, 3); + assert_equals(pointerMoveCount, 3); + }); + testTouchMove.done(); +} + +function testTouchMoveSuppressionInSlopRegion() { + if (window.chrome && chrome.gpuBenchmarking) { + var pointerActions = + [{source: "touch", + actions: [ + { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 1 }, + { name: "pointerMove", x: x, y: y + 10 }, + { name: "pointerMove", x: x, y: y + 20 }]}]; + chrome.gpuBenchmarking.pointerActionSequence(pointerActions, callbackValidMoveCount); + } +} + +var testTouchMove = async_test('Tests that the TouchMoves are not suppressed if the touch start is consumed.'); +box.addEventListener('touchstart', touchstartHandler); +box.addEventListener('touchmove', validTouchMoveResult); +box.addEventListener('pointermove', validPointerMoveResult); +testTouchMoveSuppressionInSlopRegion(); + +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html index 6306b2c..e7432e25 100644 --- a/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html +++ b/third_party/WebKit/LayoutTests/fast/events/pointerevents/pointer-event-in-slop-region.html
@@ -38,7 +38,7 @@ function callbackValidMoveCount() { testTouchMove.step(function () { assert_equals(touchMoveCount, 3); - assert_equals(pointerMoveCount, 5); + assert_equals(pointerMoveCount, 7); }); testTouchMove.done(); } @@ -49,11 +49,13 @@ [{source: "touch", actions: [ { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 1 }, { name: "pointerMove", x: x, y: y + 10 }, { name: "pointerMove", x: x, y: y + 20 }, { name: "pointerMove", x: x, y: y + 10 }, { name: "pointerUp" }, { name: "pointerDown", x: x, y: y }, + { name: "pointerMove", x: x, y: y + 1 }, { name: "pointerMove", x: x, y: y + 10 }, { name: "pointerMove", x: x, y: y + 20 }]}]; chrome.gpuBenchmarking.pointerActionSequence(pointerActions, callbackValidMoveCount);
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index 3567c9a6..5a50fac 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -316,7 +316,8 @@ if (imageElementFromImageDocument(frame().document())) return true; FrameSelection& selection = frame().selection(); - return selection.isRange() && !selection.isInPasswordField(); + return selection.computeVisibleSelectionInDOMTreeDeprecated().isRange() && + !selection.isInPasswordField(); } bool Editor::canPaste() const { @@ -325,7 +326,8 @@ bool Editor::canDelete() const { FrameSelection& selection = frame().selection(); - return selection.isRange() && selection.rootEditableElement(); + return selection.computeVisibleSelectionInDOMTreeDeprecated().isRange() && + selection.rootEditableElement(); } bool Editor::smartInsertDeleteEnabled() const { @@ -353,7 +355,10 @@ return false; EditingState editingState; - if (frame().selection().isRange()) { + if (frame() + .selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange()) { if (isTypingAction) { DCHECK(frame().document()); TypingCommand::deleteKeyPressed(
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h index 87be069..e13838a 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.h +++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -211,9 +211,6 @@ bool isNone() const { return computeVisibleSelectionInDOMTreeDeprecated().isNone(); } - bool isRange() const { - return computeVisibleSelectionInDOMTreeDeprecated().isRange(); - } bool isInPasswordField() const; bool isDirectional() const { return selectionInDOMTree().isDirectional(); }
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp index be8d850..88d9742 100644 --- a/third_party/WebKit/Source/core/editing/SelectionController.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -725,7 +725,7 @@ if (event.event().button != WebPointerProperties::Button::Left) return false; - if (selection().isRange()) { + if (selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()) { // A double-click when range is already selected // should not change the selection. So, do not call // selectClosestWordFromMouseEvent, but do set @@ -853,7 +853,7 @@ if (m_mouseDownWasSingleClickInSelection && m_selectionState != SelectionState::ExtendedSelection && dragStartPos == flooredIntPoint(event.event().positionInRootFrame()) && - selection().isRange() && + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange() && event.event().button != WebPointerProperties::Button::Right) { // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details.
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp index e20f2f310..b86f321e 100644 --- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -420,7 +420,7 @@ selection.computeVisibleSelectionInDOMTreeDeprecated().start(), tagName)) return TrueTriState; - } else if (selection.isRange()) { + } else if (selection.computeVisibleSelectionInDOMTreeDeprecated().isRange()) { Element* startElement = enclosingElementWithTag( selection.computeVisibleSelectionInDOMTreeDeprecated().start(), tagName); @@ -1939,7 +1939,10 @@ // We should update selection to canonicalize with current layout and style, // before accessing |FrameSelection::selection()|. frame.selection().updateIfNeeded(); - return frame.selection().isRange() && frame.selection().isContentEditable(); + return frame.selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange() && + frame.selection().isContentEditable(); } static bool enabledRangeInRichlyEditableText(LocalFrame& frame, @@ -1950,7 +1953,9 @@ // We should update selection to canonicalize with current layout and style, // before accessing |FrameSelection::selection()|. frame.selection().updateIfNeeded(); - return frame.selection().isRange() && + return frame.selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange() && frame.selection() .computeVisibleSelectionInDOMTreeDeprecated() .isContentRichlyEditable();
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp index ab9a3abc..a1a928da 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -153,7 +153,9 @@ LocalFrame* frame = document.frame(); DCHECK(frame); - if (!frame->selection().isRange()) + if (!frame->selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange()) return; if (TypingCommand* lastTypingCommand =
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index b698e348..6d585396 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -725,7 +725,7 @@ } std::unique_ptr<DragImage> LocalFrame::dragImageForSelection(float opacity) { - if (!selection().isRange()) + if (!selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()) return nullptr; m_view->updateAllLifecyclePhasesExceptPaint();
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp index 546d8a5c..80deafa 100644 --- a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
@@ -168,7 +168,9 @@ // Check if there is a selection and click is not on the // selection. if (layoutObject() && layoutObject()->isSelectable() && - frame->selection().isRange() && + frame->selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange() && !frame->eventHandler() .selectionController() .mouseDownWasSingleClickInSelection())
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp index df5a192..dd2b05ff 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
@@ -188,6 +188,14 @@ return m_parserBlockingScript->isReady(); } +// This has two callers and corresponds to different concepts in the spec: +// - When called from executeParsingBlockingScripts(), this corresponds to some +// steps of the "Otherwise" Clause of 'An end tag whose tag name is "script"' +// https://html.spec.whatwg.org/#scriptEndTag +// - When called from executeScriptsWaitingForParsing(), this corresponds +// https://html.spec.whatwg.org/#execute-the-script-block +// and thus currently this function does more than specced. +// TODO(hiroshige): Make the spec and implementation consistent. void HTMLParserScriptRunner::executePendingScriptAndDispatchEvent( PendingScript* pendingScript, ScriptStreamer::Type pendingScriptType) { @@ -214,16 +222,24 @@ TextPosition scriptStartPosition = pendingScript->startingPosition(); double scriptParserBlockingTime = pendingScript->parserBlockingLoadStartTime(); - // Clear the pending script before possible re-entrancy from executeScript() Element* element = pendingScript->element(); + + // 1. "Let the script be the pending parsing-blocking script. + // There is no longer a pending parsing-blocking script." + // Clear the pending script before possible re-entrancy from executeScript() pendingScript->dispose(); if (ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element)) { + // 7. "Increment the parser's script nesting level by one (it should be + // zero before this step, so this sets it to one)." HTMLParserReentryPermit::ScriptNestingLevelIncrementer nestingLevelIncrementer = m_reentryPermit->incrementScriptNestingLevel(); + IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document); + + // 8. "Execute the script." if (errorOccurred) { TRACE_EVENT_WITH_FLOW1( "blink", "HTMLParserScriptRunner ExecuteScriptFailed", element, @@ -244,6 +260,12 @@ element->dispatchEvent(Event::create(EventTypeNames::load)); } } + + // 9. "Decrement the parser's script nesting level by one. + // If the parser's script nesting level is zero + // (which it always should be at this point), + // then set the parser pause flag to false." + // This is implemented by ~ScriptNestingLevelIncrementer(). } DCHECK(!isExecutingScript()); @@ -344,8 +366,9 @@ m_host->notifyScriptLoaded(pendingScript); } -// Implements the steps for 'An end tag whose tag name is "script"' -// http://whatwg.org/html#scriptEndTag +// 'An end tag whose tag name is "script"' +// https://html.spec.whatwg.org/#scriptEndTag +// // Script handling lives outside the tree builder to keep each class simple. void HTMLParserScriptRunner::processScriptElement( Element* scriptElement, @@ -358,16 +381,27 @@ bool hadPreloadScanner = m_host->hasPreloadScanner(); + // Initial steps of 'An end tag whose tag name is "script"'. // Try to execute the script given to us. processScriptElementInternal(scriptElement, scriptStartPosition); + // "At this stage, if there is a pending parsing-blocking script, then:" if (hasParserBlockingScript()) { + // - "If the script nesting level is not zero:" if (isExecutingScript()) { + // "Set the parser pause flag to true, and abort the processing of any + // nested invocations of the tokenizer, yielding control back to the + // caller. (Tokenization will resume when the caller returns to the + // "outer" tree construction stage.)" + // TODO(hiroshige): set the parser pause flag to true here. + // Unwind to the outermost HTMLParserScriptRunner::processScriptElement // before continuing parsing. return; } + // - "Otherwise": + traceParserBlockingScript(m_parserBlockingScript.get(), !m_document->isScriptExecutionReady()); m_parserBlockingScript->markParserBlockingLoadStartTime(); @@ -376,6 +410,7 @@ // current insertion point. Append it and scan. if (!hadPreloadScanner && m_host->hasPreloadScanner()) m_host->appendCurrentInputStreamToPreloadScannerAndScan(); + executeParsingBlockingScripts(); } } @@ -384,15 +419,37 @@ return !!m_parserBlockingScript->element(); } +// The "Otherwise" Clause of 'An end tag whose tag name is "script"' +// https://html.spec.whatwg.org/#scriptEndTag void HTMLParserScriptRunner::executeParsingBlockingScripts() { + // 3. "If (1) the parser's Document has a style sheet that is blocking scripts + // or (2) the script's "ready to be parser-executed" flag is not set: + // spin the event loop + // until the parser's Document has no style sheet that is blocking scripts + // and the script's "ready to be parser-executed" flag is set." + // + // These conditions correspond to isParserBlockingScriptReady() and + // if it is false, executeParsingBlockingScripts() will be called later + // when isParserBlockingScriptReady() becomes true: + // (1) from HTMLParserScriptRunner::executeScriptsWaitingForResources(), or + // (2) from HTMLParserScriptRunner::executeScriptsWaitingForLoad(). while (hasParserBlockingScript() && isParserBlockingScriptReady()) { DCHECK(m_document); DCHECK(!isExecutingScript()); DCHECK(m_document->isScriptExecutionReady()); + // 6. "Let the insertion point be just before the next input character." InsertionPointRecord insertionPointRecord(m_host->inputStream()); + + // 1., 7.--9. executePendingScriptAndDispatchEvent(m_parserBlockingScript.get(), ScriptStreamer::ParsingBlocking); + + // 10. "Let the insertion point be undefined again." + // Implemented as ~InsertionPointRecord(). + + // 11. "If there is once again a pending parsing-blocking script, then + // repeat these steps from step 1." } } @@ -415,13 +472,23 @@ executeParsingBlockingScripts(); } +// Step 3 of https://html.spec.whatwg.org/#the-end: +// "If the list of scripts that will execute when the document has +// finished parsing is not empty, run these substeps:" bool HTMLParserScriptRunner::executeScriptsWaitingForParsing() { TRACE_EVENT0("blink", "HTMLParserScriptRunner::executeScriptsWaitingForParsing"); + while (!m_scriptsToExecuteAfterParsing.isEmpty()) { DCHECK(!isExecutingScript()); DCHECK(!hasParserBlockingScript()); DCHECK(m_scriptsToExecuteAfterParsing.first()->resource()); + + // 1. "Spin the event loop until the first script in the list of scripts + // that will execute when the document has finished parsing + // has its "ready to be parser-executed" flag set and + // the parser's Document has no style sheet that is blocking scripts." + // TODO(hiroshige): Is the latter part checked anywhere? if (!m_scriptsToExecuteAfterParsing.first()->isReady()) { m_scriptsToExecuteAfterParsing.first()->watchForLoad(this); traceParserBlockingScript(m_scriptsToExecuteAfterParsing.first().get(), @@ -429,11 +496,23 @@ m_scriptsToExecuteAfterParsing.first()->markParserBlockingLoadStartTime(); return false; } + + // 3. "Remove the first script element from the list of scripts that will + // execute when the document has finished parsing (i.e. shift out the + // first entry in the list)." PendingScript* first = m_scriptsToExecuteAfterParsing.takeFirst(); + + // 2. "Execute the first script in the list of scripts that will execute + // when the document has finished parsing." executePendingScriptAndDispatchEvent(first, ScriptStreamer::Deferred); + // FIXME: What is this m_document check for? if (!m_document) return false; + + // 4. "If the list of scripts that will execute when the document has + // finished parsing is still not empty, repeat these substeps again + // from substep 1." } return true; } @@ -504,8 +583,8 @@ return true; } -// Implements the initial steps for 'An end tag whose tag name is "script"' -// http://whatwg.org/html#scriptEndTag +// The initial steps for 'An end tag whose tag name is "script"' +// https://html.spec.whatwg.org/#scriptEndTag void HTMLParserScriptRunner::processScriptElementInternal( Element* script, const TextPosition& scriptStartPosition) { @@ -527,11 +606,20 @@ if (!isExecutingScript()) Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate()); + // "Let the old insertion point have the same value as the current + // insertion point. + // Let the insertion point be just before the next input character." InsertionPointRecord insertionPointRecord(m_host->inputStream()); + + // "Increment the parser's script nesting level by one." HTMLParserReentryPermit::ScriptNestingLevelIncrementer nestingLevelIncrementer = m_reentryPermit->incrementScriptNestingLevel(); + // "Prepare the script. This might cause some script to execute, which + // might cause new characters to be inserted into the tokenizer, and + // might cause the tokenizer to output more tokens, resulting in a + // reentrant invocation of the parser." scriptLoader->prepareScript(scriptStartPosition); // A part of Step 23 of https://html.spec.whatwg.org/#prepare-a-script: @@ -567,6 +655,14 @@ // 2nd Clause of Step 23. requestParsingBlockingScript(script); } + + // "Decrement the parser's script nesting level by one. + // If the parser's script nesting level is zero, then set the parser + // pause flag to false." + // Implemented by ~ScriptNestingLevelIncrementer(). + + // "Let the insertion point have the value of the old insertion point." + // Implemented by ~InsertionPointRecord(). } }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h index f61cf2f..2c9a3b9 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h
@@ -121,8 +121,11 @@ RefPtr<HTMLParserReentryPermit> m_reentryPermit; Member<Document> m_document; Member<HTMLParserScriptRunnerHost> m_host; + + // https://html.spec.whatwg.org/#pending-parsing-blocking-script Member<PendingScript> m_parserBlockingScript; - // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing + + // https://html.spec.whatwg.org/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing HeapDeque<Member<PendingScript>> m_scriptsToExecuteAfterParsing; };
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index c96ff69..29fe2e4 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1839,7 +1839,8 @@ VisualViewport& visualViewport = frameHost()->visualViewport(); if (!overrideTargetElement && start.anchorNode() && - (selection.rootEditableElement() || selection.isRange())) { + (selection.rootEditableElement() || + selection.computeVisibleSelectionInDOMTreeDeprecated().isRange())) { // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details. doc->updateStyleAndLayoutIgnorePendingStylesheets();
diff --git a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp index 7055cd55..0d46806 100644 --- a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp +++ b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
@@ -134,7 +134,8 @@ mouseUpEvent.setFrameScale(1); document().frame()->eventHandler().handleMouseReleaseEvent(mouseUpEvent); - ASSERT_TRUE(selection().isRange()); + ASSERT_TRUE( + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()); Range* range = createRange(selection() .computeVisibleSelectionInDOMTreeDeprecated() .toNormalizedEphemeralRange()); @@ -161,7 +162,8 @@ // like multi-click events. TapEventBuilder doubleTapEvent(IntPoint(0, 0), 2); document().frame()->eventHandler().handleGestureEvent(doubleTapEvent); - ASSERT_TRUE(selection().isRange()); + ASSERT_TRUE( + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()); EXPECT_EQ(Position(line, 0), selection().start()); if (document().frame()->editor().isSelectTrailingWhitespaceEnabled()) { EXPECT_EQ(Position(line, 4), @@ -175,7 +177,8 @@ TapEventBuilder tripleTapEvent(IntPoint(0, 0), 3); document().frame()->eventHandler().handleGestureEvent(tripleTapEvent); - ASSERT_TRUE(selection().isRange()); + ASSERT_TRUE( + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()); EXPECT_EQ(Position(line, 0), selection().start()); EXPECT_EQ(Position(line, 13), selection().computeVisibleSelectionInDOMTreeDeprecated().end()); @@ -401,7 +404,8 @@ document().frame()->eventHandler().handleMousePressEvent( doubleClickMousePressEvent); - ASSERT_TRUE(selection().isRange()); + ASSERT_TRUE( + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()); ASSERT_FALSE(selection().isHandleVisible()); MousePressEventBuilder tripleClickMousePressEvent( @@ -409,7 +413,8 @@ document().frame()->eventHandler().handleMousePressEvent( tripleClickMousePressEvent); - ASSERT_TRUE(selection().isRange()); + ASSERT_TRUE( + selection().computeVisibleSelectionInDOMTreeDeprecated().isRange()); ASSERT_FALSE(selection().isHandleVisible()); }
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp index 2be66b1a..524f298 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp +++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -425,7 +425,10 @@ // be focused if the user does a mouseup over it, however, because the // mouseup will set a selection inside it, which will call // FrameSelection::setFocusedNodeIfNeeded. - if (element && m_frame->selection().isRange()) { + if (element && + m_frame->selection() + .computeVisibleSelectionInDOMTreeDeprecated() + .isRange()) { // TODO(yosin) We should not create |Range| object for calling // |isNodeFullyContained()|. if (createRange(m_frame->selection()
diff --git a/third_party/WebKit/Source/core/input/TouchEventManager.cpp b/third_party/WebKit/Source/core/input/TouchEventManager.cpp index 149cff36..2d91d07 100644 --- a/third_party/WebKit/Source/core/input/TouchEventManager.cpp +++ b/third_party/WebKit/Source/core/input/TouchEventManager.cpp
@@ -126,10 +126,6 @@ // http://www.w3.org/TR/touch-events/#touchevent-interface for how these // lists fit together. - // Suppress all the touch moves in the slop region. - if (IsTouchSequenceStart(event)) - m_suppressingTouchmovesWithinSlop = true; - if (event.type() == WebInputEvent::TouchEnd || event.type() == WebInputEvent::TouchCancel || event.touchesLength > 1) { m_suppressingTouchmovesWithinSlop = false; @@ -292,6 +288,12 @@ } } + // Do not suppress any touchmoves if the touchstart is consumed. + if (IsTouchSequenceStart(event) && + eventResult == WebInputEventResult::NotHandled) { + m_suppressingTouchmovesWithinSlop = true; + } + return eventResult; }
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp index 4622e1d..9483dab 100644 --- a/third_party/WebKit/Source/core/page/DragController.cpp +++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -199,7 +199,8 @@ bool DragController::dragIsMove(FrameSelection& selection, DragData* dragData) { return m_documentUnderMouse == m_dragInitiator && - selection.isContentEditable() && selection.isRange() && + selection.isContentEditable() && + selection.computeVisibleSelectionInDOMTreeDeprecated().isRange() && !isCopyKeyDown(dragData); }
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index 89d55678..7a1c25a 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1149,7 +1149,8 @@ bool WebLocalFrameImpl::selectWordAroundCaret() { TRACE_EVENT0("blink", "WebLocalFrameImpl::selectWordAroundCaret"); FrameSelection& selection = frame()->selection(); - if (selection.isNone() || selection.isRange()) + if (selection.isNone() || + selection.computeVisibleSelectionInDOMTreeDeprecated().isRange()) return false; // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py index 9755e045..ead67e11 100644 --- a/tools/chrome_proxy/webdriver/video.py +++ b/tools/chrome_proxy/webdriver/video.py
@@ -42,6 +42,37 @@ self.assertHasChromeProxyViaHeader(response) self.assertTrue(saw_video_response, 'No video request seen in test!') + # Check the compressed video has the same frame count, width, height, and + # duration as uncompressed. + def testVideoMetrics(self): + expected = { + 'duration': 3.124, + 'webkitDecodedFrameCount': 54.0, + 'videoWidth': 1280.0, + 'videoHeight': 720.0 + } + with TestDriver() as t: + t.AddChromeArg('--enable-spdy-proxy-auth') + t.LoadURL('http://check.googlezip.net/cacheable/video/buck_bunny_tiny.html') + # Check request was proxied and we got a compressed video back. + for response in t.GetHTTPResponses(): + self.assertHasChromeProxyViaHeader(response) + if ('content-type' in response.response_headers + and 'video' in response.response_headers['content-type']): + self.assertEqual('video/webm', + response.response_headers['content-type']) + t.ExecuteJavascriptStatement( + 'document.querySelectorAll("video")[0].play()') + # Wait for the video to finish playing, plus some headroom. + time.sleep(5) + # Check each metric against its expected value. + for metric in expected: + actual = float(t.ExecuteJavascriptStatement( + 'document.querySelectorAll("video")[0].%s' % metric)) + self.assertAlmostEqual(expected[metric], actual, msg="Compressed video " + "metric doesn't match expected! Metric=%s Expected=%f Actual=%f" + % (metric, expected[metric], actual), places=None, delta=0.001) + # Check the frames of a compressed video. def testVideoFrames(self): self.instrumentedVideoTest('http://check.googlezip.net/cacheable/video/buck_bunny_640x360_24fps_video.html')
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 48e0bb9b..5aaf095 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -73156,6 +73156,13 @@ <summary>Reason a scavenge garbage collection was started in V8.</summary> </histogram> +<histogram name="V8.GCYoungGenerationHandling" enum="YoungGenerationHandling"> + <owner>mlippautz@chromium.org</owner> + <summary> + Type of garbage collection strategy used to collect the young generation. + </summary> +</histogram> + <histogram name="V8.Initializer.LoadV8Snapshot.Result" enum="V8InitializerLoadV8SnapshotResult"> <owner>oth@chromium.org</owner> @@ -112104,6 +112111,11 @@ <int value="1" label="XMLHttpRequestSendArrayBufferView"/> </enum> +<enum name="YoungGenerationHandling" type="int"> + <int value="0" label="Regular Scavenge"/> + <int value="1" label="Scavenge using fast promotion mode"/> +</enum> + <enum name="YouTubeRewriteStatus" type="int"> <int value="0" label="Success">Embed was properly rewritten.</int> <int value="1" label="Success, params were rewritten"> @@ -119225,6 +119237,12 @@ <histogram_suffixes name="ScrollUpdateHandledThread"> <suffix name="Main" label="ScrollUpdate handled on main thread"/> <suffix name="Impl" label="ScrollUpdate handled on impl thread"/> + <affected-histogram + name="Event.Latency.ScrollBegin.Touch.HandledToRendererSwap2"/> + <affected-histogram name="Event.Latency.ScrollBegin.Touch.TimeToHandled2"/> + <affected-histogram + name="Event.Latency.ScrollBegin.Wheel.HandledToRendererSwap2"/> + <affected-histogram name="Event.Latency.ScrollBegin.Wheel.TimeToHandled2"/> <affected-histogram name="Event.Latency.ScrollUpdate.HandledToRendererSwap"/> <affected-histogram name="Event.Latency.ScrollUpdate.Touch.HandledToRendererSwap2"/>
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py index aa0a077..3ba750a 100644 --- a/tools/perf/benchmarks/battor.py +++ b/tools/perf/benchmarks/battor.py
@@ -65,23 +65,6 @@ return 'battor.power_cases' -@benchmark.Disabled('all') # crbug.com/651384. -class BattOrPowerCasesNoChromeTrace(_BattOrBenchmark): - page_set = page_sets.power_cases.PowerCasesPageSet - - def CreateTimelineBasedMeasurementOptions(self): - options = timeline_based_measurement.Options() - options.config.enable_battor_trace = True - options.config.enable_chrome_trace = False - options.config.chrome_trace_config.SetDefaultOverheadFilter() - options.SetTimelineBasedMetrics(['powerMetric', 'clockSyncLatencyMetric']) - return options - - @classmethod - def Name(cls): - return 'battor.power_cases_no_chrome_trace' - - @benchmark.Enabled('mac') class BattOrTrivialPages(_BattOrBenchmark):
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 332eeb5..2d9f7b2 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -265,7 +265,6 @@ "controls/table/table_view.cc", "controls/table/table_view.h", "controls/table/table_view_observer.h", - "controls/table/table_view_row_background_painter.h", "controls/textfield/textfield.cc", "controls/textfield/textfield.h", "controls/textfield/textfield_controller.cc",
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc index db200b5..94fe60c 100644 --- a/ui/views/controls/table/table_view.cc +++ b/ui/views/controls/table/table_view.cc
@@ -28,7 +28,6 @@ #include "ui/views/controls/table/table_header.h" #include "ui/views/controls/table/table_utils.h" #include "ui/views/controls/table/table_view_observer.h" -#include "ui/views/controls/table/table_view_row_background_painter.h" // Padding around the text (on each side). static const int kTextVerticalPadding = 3; @@ -180,11 +179,6 @@ return scroll_view; } -void TableView::SetRowBackgroundPainter( - std::unique_ptr<TableViewRowBackgroundPainter> painter) { - row_background_painter_ = std::move(painter); -} - void TableView::SetGrouper(TableGrouper* grouper) { grouper_ = grouper; SortItemsAndUpdateMapping(); @@ -550,13 +544,8 @@ for (int i = region.min_row; i < region.max_row; ++i) { const int model_index = ViewToModel(i); const bool is_selected = selection_model_.IsSelected(model_index); - if (is_selected) { + if (is_selected) canvas->FillRect(GetRowBounds(i), selected_bg_color); - } else if (row_background_painter_) { - row_background_painter_->PaintRowBackground(model_index, - GetRowBounds(i), - canvas); - } if (selection_model_.active() == model_index && HasFocus()) canvas->DrawFocusRect(GetRowBounds(i)); for (int j = region.min_column; j < region.max_column; ++j) {
diff --git a/ui/views/controls/table/table_view.h b/ui/views/controls/table/table_view.h index 6d1c184..e6524ecf 100644 --- a/ui/views/controls/table/table_view.h +++ b/ui/views/controls/table/table_view.h
@@ -5,7 +5,6 @@ #ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_ #define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_VIEWS_H_ -#include <memory> #include <vector> #include "base/macros.h" @@ -37,7 +36,6 @@ class TableGrouper; class TableHeader; class TableViewObserver; -class TableViewRowBackgroundPainter; class TableViewTestHelper; // The cells in the first column of a table can contain: @@ -106,9 +104,6 @@ // Returns a new ScrollView that contains the receiver. View* CreateParentIfNecessary(); - void SetRowBackgroundPainter( - std::unique_ptr<TableViewRowBackgroundPainter> painter); - // Sets the TableGrouper. TableView does not own |grouper| (common use case is // to have TableModel implement TableGrouper). void SetGrouper(TableGrouper* grouper); @@ -347,8 +342,6 @@ std::vector<int> view_to_model_; std::vector<int> model_to_view_; - std::unique_ptr<TableViewRowBackgroundPainter> row_background_painter_; - TableGrouper* grouper_; // True if in SetVisibleColumnWidth().
diff --git a/ui/views/controls/table/table_view_row_background_painter.h b/ui/views/controls/table/table_view_row_background_painter.h deleted file mode 100644 index f904131..0000000 --- a/ui/views/controls/table/table_view_row_background_painter.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_ROW_BACKGROUND_PAINTER_H_ -#define UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_ROW_BACKGROUND_PAINTER_H_ - -#include "ui/views/views_export.h" - -namespace gfx { -class Canvas; -class Rect; -} - -namespace views { - -// TableViewRowBackgroundPainter is used to paint the background of a row in the -// table. -class VIEWS_EXPORT TableViewRowBackgroundPainter { - public: - virtual ~TableViewRowBackgroundPainter() {} - virtual void PaintRowBackground(int model_index, - const gfx::Rect& row_bounds, - gfx::Canvas* canvas) = 0; -}; - -} - -#endif // UI_VIEWS_CONTROLS_TABLE_TABLE_VIEW_ROW_BACKGROUND_PAINTER_H_