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

#include "chrome/browser/cocoa/status_bubble_mac.h"

#include "app/gfx/text_elider.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/cocoa/bubble_view.h"
#include "googleurl/src/gurl.h"
#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
#import "third_party/GTM/AppKit/GTMTheme.h"

namespace {

const int kWindowHeight = 18;
// The width of the bubble in relation to the width of the parent window.
const float kWindowWidthPercent = 1.0f/3.0f;

// How close the mouse can get to the infobubble before it starts sliding
// off-screen.
const int kMousePadding = 20;

const int kTextPadding = 3;

// How long each fade should last for.
const int kShowFadeDuration = 0.120f;
const int kHideFadeDuration = 0.200f;

}

// TODO(avi):
// - do display delay

StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
    : parent_(parent),
      delegate_(delegate),
      window_(nil),
      status_text_(nil),
      url_text_(nil),
      is_download_shelf_visible_(false) {
}

StatusBubbleMac::~StatusBubbleMac() {
  Hide();
}

void StatusBubbleMac::SetStatus(const std::wstring& status) {
  Create();

  NSString* status_ns = base::SysWideToNSString(status);

  SetStatus(status_ns, false);
}

void StatusBubbleMac::SetURL(const GURL& url, const std::wstring& languages) {
  Create();

  NSRect frame = [window_ frame];
  int text_width = static_cast<int>(frame.size.width -
                                    kBubbleViewTextPositionX -
                                    kTextPadding);
  NSFont* font = [[window_ contentView] font];
  gfx::Font font_chr =
      gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
                            [font pointSize]);

  std::wstring status = gfx::ElideUrl(url, font_chr, text_width, languages);
  NSString* status_ns = base::SysWideToNSString(status);

  SetStatus(status_ns, true);
}

void StatusBubbleMac::SetStatus(NSString* status, bool is_url) {
  NSString** main;
  NSString** backup;

  if (is_url) {
    main = &url_text_;
    backup = &status_text_;
  } else {
    main = &status_text_;
    backup = &url_text_;
  }

  if ([status isEqualToString:*main])
    return;

  [*main release];
  *main = [status retain];
  if ([*main length] > 0) {
    [[window_ contentView] setContent:*main];
  } else if ([*backup length] > 0) {
    [[window_ contentView] setContent:*backup];
  } else {
    Hide();
  }

  FadeIn();
}

void StatusBubbleMac::Hide() {
  FadeOut();

  if (window_) {
    [parent_ removeChildWindow:window_];
    [window_ release];
    window_ = nil;
  }

  [status_text_ release];
  status_text_ = nil;
  [url_text_ release];
  url_text_ = nil;
}

void StatusBubbleMac::MouseMoved() {
  if (!window_)
    return;

  NSPoint cursor_location = [NSEvent mouseLocation];
  --cursor_location.y;  // docs say the y coord starts at 1 not 0; don't ask why

  // Get the normal position of the frame.
  NSRect window_frame = [window_ frame];
  window_frame.origin = [parent_ frame].origin;

  // Get the cursor position relative to the popup.
  cursor_location.x -= NSMaxX(window_frame);
  cursor_location.y -= NSMaxY(window_frame);

  // If the mouse is in a position where we think it would move the
  // status bubble, figure out where and how the bubble should be moved.
  if (cursor_location.y < kMousePadding &&
      cursor_location.x < kMousePadding) {
    int offset = kMousePadding - cursor_location.y;

    // Make the movement non-linear.
    offset = offset * offset / kMousePadding;

    // When the mouse is entering from the right, we want the offset to be
    // scaled by how horizontally far away the cursor is from the bubble.
    if (cursor_location.x > 0) {
      offset = offset * ((kMousePadding - cursor_location.x) / kMousePadding);
    }

    // Cap the offset and change the visual presentation of the bubble
    // depending on where it ends up (so that rounded corners square off
    // and mate to the edges of the tab content).
    if (offset >= NSHeight(window_frame)) {
      offset = NSHeight(window_frame);
      [[window_ contentView] setCornerFlags:
          kRoundedBottomLeftCorner | kRoundedBottomRightCorner];
    } else if (offset > 0) {
      [[window_ contentView] setCornerFlags:
          kRoundedTopRightCorner | kRoundedBottomLeftCorner |
          kRoundedBottomRightCorner];
    } else {
      [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
    }

    offset_ = offset;
    window_frame.origin.y -= offset;
  } else {
    offset_ = 0;
    [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
  }

  // |delegate_| can be nil during unit tests.
  if (is_download_shelf_visible_) {
    if ([delegate_ respondsToSelector:@selector(verticalOffsetForStatusBubble)])
      window_frame.origin.y += [delegate_ verticalOffsetForStatusBubble];
  }

  [window_ setFrame:window_frame display:YES];
}

void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
  is_download_shelf_visible_ = visible;
}

void StatusBubbleMac::Create() {
  if (window_)
    return;

  NSRect rect = [parent_ frame];
  rect.size.height = kWindowHeight;
  rect.size.width = static_cast<int>(kWindowWidthPercent * rect.size.width);
  // TODO(avi):fix this for RTL
  window_ = [[NSWindow alloc] initWithContentRect:rect
                                        styleMask:NSBorderlessWindowMask
                                          backing:NSBackingStoreBuffered
                                            defer:YES];
  [window_ setMovableByWindowBackground:NO];<commit_msg>Committing original patch http://codereview.chromium.org/178036 by <NAME>.<commit_after>// Copyright (c) 2009 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.

#include "chrome/browser/cocoa/status_bubble_mac.h"

#include "app/gfx/text_elider.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/cocoa/bubble_view.h"
#include "googleurl/src/gurl.h"
#import "third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.h"
#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
#import "third_party/GTM/AppKit/GTMTheme.h"

namespace {

const int kWindowHeight = 18;
// The width of the bubble in relation to the width of the parent window.
const float kWindowWidthPercent = 1.0f/3.0f;

// How close the mouse can get to the infobubble before it starts sliding
// off-screen.
const int kMousePadding = 20;

const int kTextPadding = 3;

// How long each fade should last for.
const int kShowFadeDuration = 0.120f;
const int kHideFadeDuration = 0.200f;

}

// TODO(avi):
// - do display delay

StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
    : parent_(parent),
      delegate_(delegate),
      window_(nil),
      status_text_(nil),
      url_text_(nil),
      is_download_shelf_visible_(false) {
}

StatusBubbleMac::~StatusBubbleMac() {
  Hide();
}

void StatusBubbleMac::SetStatus(const std::wstring& status) {
  Create();

  NSString* status_ns = base::SysWideToNSString(status);

  SetStatus(status_ns, false);
}

void StatusBubbleMac::SetURL(const GURL& url, const std::wstring& languages) {
  Create();

  NSRect frame = [window_ frame];
  int text_width = static_cast<int>(frame.size.width -
                                    kBubbleViewTextPositionX -
                                    kTextPadding);
  NSFont* font = [[window_ contentView] font];
  gfx::Font font_chr =
      gfx::Font::CreateFont(base::SysNSStringToWide([font fontName]),
                            [font pointSize]);

  std::wstring status = gfx::ElideUrl(url, font_chr, text_width, languages);
  NSString* status_ns = base::SysWideToNSString(status);

  SetStatus(status_ns, true);
}

void StatusBubbleMac::SetStatus(NSString* status, bool is_url) {
  NSString** main;
  NSString** backup;

  if (is_url) {
    main = &url_text_;
    backup = &status_text_;
  } else {
    main = &status_text_;
    backup = &url_text_;
  }

  if ([status isEqualToString:*main])
    return;

  [*main release];
  *main = [status retain];
  if ([*main length] > 0) {
    [[window_ contentView] setContent:*main];
  } else if ([*backup length] > 0) {
    [[window_ contentView] setContent:*backup];
  } else {
    Hide();
  }

  FadeIn();
}

void StatusBubbleMac::Hide() {
  FadeOut();

  if (window_) {
    [parent_ removeChildWindow:window_];
    [window_ release];
    window_ = nil;
  }

  [status_text_ release];
  status_text_ = nil;
  [url_text_ release];
  url_text_ = nil;
}

void StatusBubbleMac::MouseMoved() {
  if (!window_)
    return;

  NSPoint cursor_location = [NSEvent mouseLocation];
  --cursor_location.y;  // docs say the y coord starts at 1 not 0; don't ask why

  // Get the normal position of the frame.
  NSRect window_frame = [window_ frame];
  window_frame.origin = [parent_ frame].origin;

  // Adjust the position to sit on top of download shelf.
  // |delegate_| can be nil during unit tests.
  if (is_download_shelf_visible_) {
    if ([delegate_ respondsToSelector:@selector(verticalOffsetForStatusBubble)])
      window_frame.origin.y += [delegate_ verticalOffsetForStatusBubble];
  }

  // Get the cursor position relative to the popup.
  cursor_location.x -= NSMaxX(window_frame);
  cursor_location.y -= NSMaxY(window_frame);

  // If the mouse is in a position where we think it would move the
  // status bubble, figure out where and how the bubble should be moved.
  if (cursor_location.y < kMousePadding &&
      cursor_location.x < kMousePadding) {
    int offset = kMousePadding - cursor_location.y;

    // Make the movement non-linear.
    offset = offset * offset / kMousePadding;

    // When the mouse is entering from the right, we want the offset to be
    // scaled by how horizontally far away the cursor is from the bubble.
    if (cursor_location.x > 0) {
      offset = offset * ((kMousePadding - cursor_location.x) / kMousePadding);
    }

    // Cap the offset and change the visual presentation of the bubble
    // depending on where it ends up (so that rounded corners square off
    // and mate to the edges of the tab content).
    if (offset >= NSHeight(window_frame)) {
      offset = NSHeight(window_frame);
      [[window_ contentView] setCornerFlags:
          kRoundedBottomLeftCorner | kRoundedBottomRightCorner];
    } else if (offset > 0) {
      [[window_ contentView] setCornerFlags:
          kRoundedTopRightCorner | kRoundedBottomLeftCorner |
          kRoundedBottomRightCorner];
    } else {
      [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
    }

    offset_ = offset;
    window_frame.origin.y -= offset;
  } else {
    offset_ = 0;
    [[window_ contentView] setCornerFlags:kRoundedTopRightCorner];
  }

  [window_ setFrame:window_frame display:YES];
}

void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
  is_download_shelf_visible_ = visible;
}

void StatusBubbleMac::Create() {
  if (window_)
    return;

  NSRect rect = [parent_ frame];
  rect.size.height = kWindowHeight;
  rect.size.width = static_cast<int>(kWindowWidthPercent * rect.size.width);
  // TODO(avi):fix this for RTL
  window_ = [[NSWindow alloc] initWithContentRect:rect
                                        styleMask:NSBorderlessWindowMask
                                          backing:NSBackingStoreBuffered
                                            defer:YES];
  [window_ setMovableByWindowBackground:NO];
{'fraction_non_alphanumeric': 0.10598173905623347, 'fraction_numerical': 0.005290553801518901, 'mean_word_length': 3.271137026239067, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 23, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6069976', 'n_tokens_mistral': 3779, 'n_tokens_neox': 3606, 'n_words': 974}