| Index: third_party/WebKit/Source/core/page/CreateWindow.cpp
 | 
| diff --git a/third_party/WebKit/Source/core/page/CreateWindow.cpp b/third_party/WebKit/Source/core/page/CreateWindow.cpp
 | 
| index d3a42e6f25a79cf4891a8abbea211720a194fb72..88aa2ad87b0c61d0b1801499405c0d5ef3883ee8 100644
 | 
| --- a/third_party/WebKit/Source/core/page/CreateWindow.cpp
 | 
| +++ b/third_party/WebKit/Source/core/page/CreateWindow.cpp
 | 
| @@ -29,6 +29,7 @@
 | 
|  #include "bindings/core/v8/ExceptionState.h"
 | 
|  #include "core/dom/Document.h"
 | 
|  #include "core/dom/UserGestureIndicator.h"
 | 
| +#include "core/events/UIEventWithKeyState.h"
 | 
|  #include "core/frame/FrameClient.h"
 | 
|  #include "core/frame/LocalFrame.h"
 | 
|  #include "core/frame/Settings.h"
 | 
| @@ -37,16 +38,225 @@
 | 
|  #include "core/page/ChromeClient.h"
 | 
|  #include "core/page/FocusController.h"
 | 
|  #include "core/page/Page.h"
 | 
| -#include "core/page/WindowFeatures.h"
 | 
|  #include "core/probe/CoreProbes.h"
 | 
| +#include "platform/KeyboardCodes.h"
 | 
|  #include "platform/loader/fetch/ResourceRequest.h"
 | 
|  #include "platform/weborigin/KURL.h"
 | 
|  #include "platform/weborigin/SecurityOrigin.h"
 | 
|  #include "platform/weborigin/SecurityPolicy.h"
 | 
| +#include "public/platform/WebInputEvent.h"
 | 
| +#include "public/platform/WebKeyboardEvent.h"
 | 
| +#include "public/platform/WebMouseEvent.h"
 | 
|  #include "public/platform/WebURLRequest.h"
 | 
| +#include "public/web/WebWindowFeatures.h"
 | 
|  
 | 
|  namespace blink {
 | 
|  
 | 
| +namespace {
 | 
| +
 | 
| +void UpdatePolicyForEvent(const WebInputEvent* input_event,
 | 
| +                          NavigationPolicy* policy) {
 | 
| +  if (!input_event)
 | 
| +    return;
 | 
| +
 | 
| +  unsigned short button_number = 0;
 | 
| +  if (input_event->GetType() == WebInputEvent::kMouseUp) {
 | 
| +    const WebMouseEvent* mouse_event =
 | 
| +        static_cast<const WebMouseEvent*>(input_event);
 | 
| +
 | 
| +    switch (mouse_event->button) {
 | 
| +      case WebMouseEvent::Button::kLeft:
 | 
| +        button_number = 0;
 | 
| +        break;
 | 
| +      case WebMouseEvent::Button::kMiddle:
 | 
| +        button_number = 1;
 | 
| +        break;
 | 
| +      case WebMouseEvent::Button::kRight:
 | 
| +        button_number = 2;
 | 
| +        break;
 | 
| +      default:
 | 
| +        return;
 | 
| +    }
 | 
| +  } else if ((WebInputEvent::IsKeyboardEventType(input_event->GetType()) &&
 | 
| +              static_cast<const WebKeyboardEvent*>(input_event)
 | 
| +                      ->windows_key_code == VKEY_RETURN) ||
 | 
| +             WebInputEvent::IsGestureEventType(input_event->GetType())) {
 | 
| +    // Keyboard and gesture events can simulate mouse events.
 | 
| +    button_number = 0;
 | 
| +  } else {
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  bool ctrl = input_event->GetModifiers() & WebInputEvent::kControlKey;
 | 
| +  bool shift = input_event->GetModifiers() & WebInputEvent::kShiftKey;
 | 
| +  bool alt = input_event->GetModifiers() & WebInputEvent::kAltKey;
 | 
| +  bool meta = input_event->GetModifiers() & WebInputEvent::kMetaKey;
 | 
| +
 | 
| +  NavigationPolicy user_policy = *policy;
 | 
| +  NavigationPolicyFromMouseEvent(button_number, ctrl, shift, alt, meta,
 | 
| +                                 &user_policy);
 | 
| +
 | 
| +  // When the input event suggests a download, but the navigation was initiated
 | 
| +  // by script, we should not override it.
 | 
| +  if (user_policy == kNavigationPolicyDownload &&
 | 
| +      *policy != kNavigationPolicyIgnore)
 | 
| +    return;
 | 
| +
 | 
| +  // User and app agree that we want a new window; let the app override the
 | 
| +  // decorations.
 | 
| +  if (user_policy == kNavigationPolicyNewWindow &&
 | 
| +      *policy == kNavigationPolicyNewPopup)
 | 
| +    return;
 | 
| +  *policy = user_policy;
 | 
| +}
 | 
| +
 | 
| +NavigationPolicy GetNavigationPolicy(const WebInputEvent* current_event,
 | 
| +                                     bool toolbar_visible) {
 | 
| +  // If the window features didn't enable the toolbar, or this window wasn't
 | 
| +  // created by a user gesture, show as a popup instead of a new tab.
 | 
| +  //
 | 
| +  // Note: this previously also checked that menubar, resizable, scrollbar, and
 | 
| +  // statusbar are enabled too. When no feature string is specified, these
 | 
| +  // features default to enabled (and the window opens as a new tab). However,
 | 
| +  // when a feature string is specified, any *unspecified* features default to
 | 
| +  // disabled, often causing the window to open as a popup instead.
 | 
| +  //
 | 
| +  // As specifying menubar, resizable, scrollbar, and statusbar have no effect
 | 
| +  // on the UI, just ignore them and only consider whether or not the toolbar is
 | 
| +  // enabled, which matches Firefox's behavior.
 | 
| +  NavigationPolicy policy = toolbar_visible ? kNavigationPolicyNewForegroundTab
 | 
| +                                            : kNavigationPolicyNewPopup;
 | 
| +  UpdatePolicyForEvent(current_event, &policy);
 | 
| +  return policy;
 | 
| +}
 | 
| +
 | 
| +}  // anonymous namespace
 | 
| +
 | 
| +NavigationPolicy EffectiveNavigationPolicy(NavigationPolicy policy,
 | 
| +                                           const WebInputEvent* current_event,
 | 
| +                                           bool toolbar_visible) {
 | 
| +  if (policy == kNavigationPolicyIgnore)
 | 
| +    return GetNavigationPolicy(current_event, toolbar_visible);
 | 
| +  if (policy == kNavigationPolicyNewBackgroundTab &&
 | 
| +      GetNavigationPolicy(current_event, toolbar_visible) !=
 | 
| +          kNavigationPolicyNewBackgroundTab &&
 | 
| +      !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld()) {
 | 
| +    return kNavigationPolicyNewForegroundTab;
 | 
| +  }
 | 
| +  return policy;
 | 
| +}
 | 
| +
 | 
| +// Though isspace() considers \t and \v to be whitespace, Win IE doesn't when
 | 
| +// parsing window features.
 | 
| +static bool IsWindowFeaturesSeparator(UChar c) {
 | 
| +  return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' ||
 | 
| +         c == ',' || c == '\0';
 | 
| +}
 | 
| +
 | 
| +WebWindowFeatures GetWindowFeaturesFromString(const String& feature_string) {
 | 
| +  WebWindowFeatures window_features;
 | 
| +
 | 
| +  // The IE rule is: all features except for channelmode default
 | 
| +  // to YES, but if the user specifies a feature string, all features default to
 | 
| +  // NO. (There is no public standard that applies to this method.)
 | 
| +  // <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
 | 
| +  if (feature_string.IsEmpty())
 | 
| +    return window_features;
 | 
| +
 | 
| +  window_features.menu_bar_visible = false;
 | 
| +  window_features.status_bar_visible = false;
 | 
| +  window_features.tool_bar_visible = false;
 | 
| +  window_features.scrollbars_visible = false;
 | 
| +
 | 
| +  // Tread lightly in this code -- it was specifically designed to mimic Win
 | 
| +  // IE's parsing behavior.
 | 
| +  unsigned key_begin, key_end;
 | 
| +  unsigned value_begin, value_end;
 | 
| +
 | 
| +  String buffer = feature_string.DeprecatedLower();
 | 
| +  unsigned length = buffer.length();
 | 
| +  for (unsigned i = 0; i < length;) {
 | 
| +    // skip to first non-separator, but don't skip past the end of the string
 | 
| +    while (i < length && IsWindowFeaturesSeparator(buffer[i]))
 | 
| +      i++;
 | 
| +    key_begin = i;
 | 
| +
 | 
| +    // skip to first separator
 | 
| +    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
 | 
| +      i++;
 | 
| +    key_end = i;
 | 
| +
 | 
| +    SECURITY_DCHECK(i <= length);
 | 
| +
 | 
| +    // skip to first '=', but don't skip past a ',' or the end of the string
 | 
| +    while (i < length && buffer[i] != '=') {
 | 
| +      if (buffer[i] == ',')
 | 
| +        break;
 | 
| +      i++;
 | 
| +    }
 | 
| +
 | 
| +    SECURITY_DCHECK(i <= length);
 | 
| +
 | 
| +    // Skip to first non-separator, but don't skip past a ',' or the end of the
 | 
| +    // string.
 | 
| +    while (i < length && IsWindowFeaturesSeparator(buffer[i])) {
 | 
| +      if (buffer[i] == ',')
 | 
| +        break;
 | 
| +      i++;
 | 
| +    }
 | 
| +    value_begin = i;
 | 
| +
 | 
| +    SECURITY_DCHECK(i <= length);
 | 
| +
 | 
| +    // skip to first separator
 | 
| +    while (i < length && !IsWindowFeaturesSeparator(buffer[i]))
 | 
| +      i++;
 | 
| +    value_end = i;
 | 
| +
 | 
| +    SECURITY_DCHECK(i <= length);
 | 
| +
 | 
| +    String key_string(buffer.Substring(key_begin, key_end - key_begin));
 | 
| +    String value_string(buffer.Substring(value_begin, value_end - value_begin));
 | 
| +
 | 
| +    // Listing a key with no value is shorthand for key=yes
 | 
| +    int value;
 | 
| +    if (value_string.IsEmpty() || value_string == "yes")
 | 
| +      value = 1;
 | 
| +    else
 | 
| +      value = value_string.ToInt();
 | 
| +
 | 
| +    if (key_string == "left" || key_string == "screenx") {
 | 
| +      window_features.x_set = true;
 | 
| +      window_features.x = value;
 | 
| +    } else if (key_string == "top" || key_string == "screeny") {
 | 
| +      window_features.y_set = true;
 | 
| +      window_features.y = value;
 | 
| +    } else if (key_string == "width" || key_string == "innerwidth") {
 | 
| +      window_features.width_set = true;
 | 
| +      window_features.width = value;
 | 
| +    } else if (key_string == "height" || key_string == "innerheight") {
 | 
| +      window_features.height_set = true;
 | 
| +      window_features.height = value;
 | 
| +    } else if (key_string == "menubar") {
 | 
| +      window_features.menu_bar_visible = value;
 | 
| +    } else if (key_string == "toolbar" || key_string == "location") {
 | 
| +      window_features.tool_bar_visible |= static_cast<bool>(value);
 | 
| +    } else if (key_string == "status") {
 | 
| +      window_features.status_bar_visible = value;
 | 
| +    } else if (key_string == "scrollbars") {
 | 
| +      window_features.scrollbars_visible = value;
 | 
| +    } else if (key_string == "noopener") {
 | 
| +      window_features.noopener = true;
 | 
| +    } else if (key_string == "background") {
 | 
| +      window_features.background = true;
 | 
| +    } else if (key_string == "persistent") {
 | 
| +      window_features.persistent = true;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return window_features;
 | 
| +}
 | 
| +
 | 
|  static Frame* ReuseExistingWindow(LocalFrame& active_frame,
 | 
|                                    LocalFrame& lookup_frame,
 | 
|                                    const AtomicString& frame_name,
 | 
| @@ -71,13 +281,17 @@ static Frame* ReuseExistingWindow(LocalFrame& active_frame,
 | 
|  
 | 
|  static Frame* CreateNewWindow(LocalFrame& opener_frame,
 | 
|                                const FrameLoadRequest& request,
 | 
| -                              const WindowFeatures& features,
 | 
| +                              const WebWindowFeatures& features,
 | 
|                                NavigationPolicy policy,
 | 
|                                bool& created) {
 | 
|    Page* old_page = opener_frame.GetPage();
 | 
|    if (!old_page)
 | 
|      return nullptr;
 | 
|  
 | 
| +  policy = EffectiveNavigationPolicy(
 | 
| +      policy, old_page->GetChromeClient().GetCurrentInputEvent(),
 | 
| +      features.tool_bar_visible);
 | 
| +
 | 
|    Page* page = old_page->GetChromeClient().CreateWindow(&opener_frame, request,
 | 
|                                                          features, policy);
 | 
|    if (!page)
 | 
| @@ -92,7 +306,9 @@ static Frame* CreateNewWindow(LocalFrame& opener_frame,
 | 
|    if (!EqualIgnoringASCIICase(request.FrameName(), "_blank"))
 | 
|      frame.Tree().SetName(request.FrameName());
 | 
|  
 | 
| -  page->GetChromeClient().SetWindowFeatures(features);
 | 
| +  page->SetWindowFeatures(features);
 | 
| +
 | 
| +  frame.View()->SetCanHaveScrollbars(features.scrollbars_visible);
 | 
|  
 | 
|    // 'x' and 'y' specify the location of the window, while 'width' and 'height'
 | 
|    // specify the size of the viewport. We can only resize the window, so adjust
 | 
| @@ -130,10 +346,9 @@ static Frame* CreateWindowHelper(LocalFrame& opener_frame,
 | 
|                                   LocalFrame& active_frame,
 | 
|                                   LocalFrame& lookup_frame,
 | 
|                                   const FrameLoadRequest& request,
 | 
| -                                 const WindowFeatures& features,
 | 
| +                                 const WebWindowFeatures& features,
 | 
|                                   NavigationPolicy policy,
 | 
|                                   bool& created) {
 | 
| -  DCHECK(!features.dialog || request.FrameName().IsEmpty());
 | 
|    DCHECK(request.GetResourceRequest().RequestorOrigin() ||
 | 
|           opener_frame.GetDocument()->Url().IsEmpty());
 | 
|    DCHECK_EQ(request.GetResourceRequest().GetFrameType(),
 | 
| @@ -176,7 +391,7 @@ static Frame* CreateWindowHelper(LocalFrame& opener_frame,
 | 
|  
 | 
|  DOMWindow* CreateWindow(const String& url_string,
 | 
|                          const AtomicString& frame_name,
 | 
| -                        const WindowFeatures& window_features,
 | 
| +                        const String& window_features_string,
 | 
|                          LocalDOMWindow& calling_window,
 | 
|                          LocalFrame& first_frame,
 | 
|                          LocalFrame& opener_frame,
 | 
| @@ -195,6 +410,9 @@ DOMWindow* CreateWindow(const String& url_string,
 | 
|      return nullptr;
 | 
|    }
 | 
|  
 | 
| +  WebWindowFeatures window_features =
 | 
| +      GetWindowFeaturesFromString(window_features_string);
 | 
| +
 | 
|    FrameLoadRequest frame_request(calling_window.document(),
 | 
|                                   ResourceRequest(completed_url), frame_name);
 | 
|    frame_request.SetShouldSetOpener(window_features.noopener ? kNeverSetOpener
 | 
| @@ -231,7 +449,7 @@ DOMWindow* CreateWindow(const String& url_string,
 | 
|      return nullptr;
 | 
|    if (new_frame->DomWindow()->IsInsecureScriptAccess(calling_window,
 | 
|                                                       completed_url))
 | 
| -    return new_frame->DomWindow();
 | 
| +    return window_features.noopener ? nullptr : new_frame->DomWindow();
 | 
|  
 | 
|    // TODO(dcheng): Special case for window.open("about:blank") to ensure it
 | 
|    // loads synchronously into a new window. This is our historical behavior, and
 | 
| @@ -252,7 +470,7 @@ DOMWindow* CreateWindow(const String& url_string,
 | 
|                          has_user_gesture ? UserGestureStatus::kActive
 | 
|                                           : UserGestureStatus::kNone);
 | 
|    }
 | 
| -  return new_frame->DomWindow();
 | 
| +  return window_features.noopener ? nullptr : new_frame->DomWindow();
 | 
|  }
 | 
|  
 | 
|  void CreateWindowForRequest(const FrameLoadRequest& request,
 | 
| @@ -273,7 +491,7 @@ void CreateWindowForRequest(const FrameLoadRequest& request,
 | 
|    if (policy == kNavigationPolicyCurrentTab)
 | 
|      policy = kNavigationPolicyNewForegroundTab;
 | 
|  
 | 
| -  WindowFeatures features;
 | 
| +  WebWindowFeatures features;
 | 
|    features.noopener = request.GetShouldSetOpener() == kNeverSetOpener;
 | 
|    bool created;
 | 
|    Frame* new_frame =
 | 
| 
 |