<commit_before>// Copyright (c) 2010 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.

#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"

#include "base/string_util.h"
#include "grit/generated_resources.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"  // IDC_*
#include "chrome/browser/browser_list.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
#include "ui/base/l10n/l10n_util_mac.h"

@implementation AutocompleteTextFieldEditor

- (id)initWithFrame:(NSRect)frameRect {
  if ((self = [super initWithFrame:frameRect])) {
    dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);

    forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]);
  }
  return self;
}

// If the entire field is selected, drag the same data as would be
// dragged from the field's location icon.  In some cases the textual
// contents will not contain relevant data (for instance, "http://" is
// stripped from URLs).
- (BOOL)dragSelectionWithEvent:(NSEvent *)event
                        offset:(NSSize)mouseOffset
                     slideBack:(BOOL)slideBack {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer && observer->CanCopy()) {
    NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    observer->CopyToPasteboard(pboard);

    NSPoint p;
    NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p];

    [self dragImage:image
                 at:p
             offset:mouseOffset
              event:event
         pasteboard:pboard
             source:self
          slideBack:slideBack];
    return YES;
  }
  return [super dragSelectionWithEvent:event
                                offset:mouseOffset
                             slideBack:slideBack];
}

- (void)copy:(id)sender {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer && observer->CanCopy())
    observer->CopyToPasteboard([NSPasteboard generalPasteboard]);
}

- (void)cut:(id)sender {
  [self copy:sender];
  [self delete:nil];
}

// This class assumes that the delegate is an AutocompleteTextField.
// Enforce that assumption.
- (AutocompleteTextField*)delegate {
  AutocompleteTextField* delegate =
      static_cast<AutocompleteTextField*>([super delegate]);
  DCHECK(delegate == nil ||
         [delegate isKindOfClass:[AutocompleteTextField class]]);
  return delegate;
}

- (void)setDelegate:(AutocompleteTextField*)delegate {
  DCHECK(delegate == nil ||
         [delegate isKindOfClass:[AutocompleteTextField class]]);
  [super setDelegate:delegate];
}

// Convenience method for retrieving the observer from the delegate.
- (AutocompleteTextFieldObserver*)observer {
  return [[self delegate] observer];
}

- (void)paste:(id)sender {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer) {
    observer->OnPaste();
  }
}

- (void)pasteAndGo:sender {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer) {
    observer->OnPasteAndGo();
  }
}

// We have rich text, but it shouldn't be modified by the user, so
// don't update the font panel.  In theory, -setUsesFontPanel: should
// accomplish this, but that gets called frequently with YES when
// NSTextField and NSTextView synchronize their contents.  That is
// probably unavoidable because in most cases having rich text in the
// field you probably would expect it to update the font panel.
- (void)updateFontPanel {}

// No ruler bar, so don't update any of that state, either.
- (void)updateRuler {}

- (NSMenu*)menuForEvent:(NSEvent*)event {
  // Give the control a chance to provide page-action menus.
  // NOTE: Note that page actions aren't even in the editor's
  // boundaries!  The Cocoa control implementation seems to do a
  // blanket forward to here if nothing more specific is returned from
  // the control and cell calls.
  // TODO(shess): Determine if the page-action part of this can be
  // moved to the cell.<commit_msg>[Mac] Prevent pasting of huge pasteboards into Omnibox.<commit_after>// Copyright (c) 2010 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.

#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"

#include "base/string_util.h"
#include "grit/generated_resources.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"  // IDC_*
#include "chrome/browser/browser_list.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
#include "ui/base/l10n/l10n_util_mac.h"

namespace {

// When too much data is put into a single-line text field, things get
// janky due to the cost of computing the blink rect.  Sometimes users
// accidentally paste large amounts, so place a limit on what will be
// accepted.
//
// 10k characters was arbitrarily chosen by seeing how much a text
// field could handle in a single line before it started getting too
// janky to recover from (jankiness was detectable around 5k).
// www.google.com returns an error for searches around 2k characters,
// so this is conservative.
const NSUInteger kMaxPasteLength = 10000;

// Returns |YES| if too much text would be pasted.
BOOL ThePasteboardIsTooDamnBig() {
  NSPasteboard* pb = [NSPasteboard generalPasteboard];
  NSString* type =
      [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
  if (!type)
    return NO;

  return [[pb stringForType:type] length] > kMaxPasteLength;
}

}  // namespace

@implementation AutocompleteTextFieldEditor

- (id)initWithFrame:(NSRect)frameRect {
  if ((self = [super initWithFrame:frameRect])) {
    dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);

    forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]);
  }
  return self;
}

// If the entire field is selected, drag the same data as would be
// dragged from the field's location icon.  In some cases the textual
// contents will not contain relevant data (for instance, "http://" is
// stripped from URLs).
- (BOOL)dragSelectionWithEvent:(NSEvent *)event
                        offset:(NSSize)mouseOffset
                     slideBack:(BOOL)slideBack {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer && observer->CanCopy()) {
    NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    observer->CopyToPasteboard(pboard);

    NSPoint p;
    NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p];

    [self dragImage:image
                 at:p
             offset:mouseOffset
              event:event
         pasteboard:pboard
             source:self
          slideBack:slideBack];
    return YES;
  }
  return [super dragSelectionWithEvent:event
                                offset:mouseOffset
                             slideBack:slideBack];
}

- (void)copy:(id)sender {
  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer && observer->CanCopy())
    observer->CopyToPasteboard([NSPasteboard generalPasteboard]);
}

- (void)cut:(id)sender {
  [self copy:sender];
  [self delete:nil];
}

// This class assumes that the delegate is an AutocompleteTextField.
// Enforce that assumption.
- (AutocompleteTextField*)delegate {
  AutocompleteTextField* delegate =
      static_cast<AutocompleteTextField*>([super delegate]);
  DCHECK(delegate == nil ||
         [delegate isKindOfClass:[AutocompleteTextField class]]);
  return delegate;
}

- (void)setDelegate:(AutocompleteTextField*)delegate {
  DCHECK(delegate == nil ||
         [delegate isKindOfClass:[AutocompleteTextField class]]);
  [super setDelegate:delegate];
}

// Convenience method for retrieving the observer from the delegate.
- (AutocompleteTextFieldObserver*)observer {
  return [[self delegate] observer];
}

- (void)paste:(id)sender {
  if (ThePasteboardIsTooDamnBig()) {
    NSBeep();
    return;
  }

  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer) {
    observer->OnPaste();
  }
}

- (void)pasteAndGo:sender {
  if (ThePasteboardIsTooDamnBig()) {
    NSBeep();
    return;
  }

  AutocompleteTextFieldObserver* observer = [self observer];
  DCHECK(observer);
  if (observer) {
    observer->OnPasteAndGo();
  }
}

// We have rich text, but it shouldn't be modified by the user, so
// don't update the font panel.  In theory, -setUsesFontPanel: should
// accomplish this, but that gets called frequently with YES when
// NSTextField and NSTextView synchronize their contents.  That is
// probably unavoidable because in most cases having rich text in the
// field you probably would expect it to update the font panel.
- (void)updateFontPanel {}

// No ruler bar, so don't update any of that state, either.
- (void)updateRuler {}

- (NSMenu*)menuForEvent:(NSEvent*)event {
  // Give the control a chance to provide page-action menus.
  // NOTE: Note that page actions aren't even in the editor's
  // boundaries!  The Cocoa control implementation seems to do a
  // blanket forward to here if nothing more specific is returned from
  // the control and cell calls.
  // TODO(shess): Determine if the page-action part of this can be
  // moved to the cell.
{'fraction_non_alphanumeric': 0.10339273129970804, 'fraction_numerical': 0.002516862981979261, 'mean_word_length': 3.808325266214908, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6988609', 'n_tokens_mistral': 2989, 'n_tokens_neox': 2822, 'n_words': 846}