1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Copyright (c) 2011 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/drag_util.h"
#include <cmath>
#include "base/files/file_path.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/webplugininfo.h"
#include "ipc/ipc_message.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#import "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
#include "ui/resources/grit/ui_resources.h"
#include "url/gurl.h"
#include "url/url_constants.h"
using content::PluginService;
namespace drag_util {
namespace {
BOOL IsSupportedFileURL(Profile* profile, const GURL& url) {
base::FilePath full_path;
net::FileURLToFilePath(url, &full_path);
std::string mime_type;
net::GetMimeTypeFromFile(full_path, &mime_type);
// This logic mirrors |BufferedResourceHandler::ShouldDownload()|.
// TODO(asvitkine): Refactor this out to a common location instead of
// duplicating code.
if (net::IsSupportedMimeType(mime_type))
return YES;
// Check whether there is a plugin that supports the mime type. (e.g. PDF)
// TODO(bauerb): This possibly uses stale information, but it's guaranteed not
// to do disk access.
bool allow_wildcard = false;
content::WebPluginInfo plugin;
return PluginService::GetInstance()->GetPluginInfo(
-1, // process ID
MSG_ROUTING_NONE, // routing ID
profile->GetResourceContext(),
url, GURL(), mime_type, allow_wildcard,
NULL, &plugin, NULL);
}
// Draws string |title| within box |frame|, positioning it at the origin.
// Truncates text with fading if it is too long to fit horizontally.
// Based on code from GradientButtonCell but simplified where possible.
void DrawTruncatedTitle(NSAttributedString* title, NSRect frame) {
NSSize size = [title size];
if (std::floor(size.width) <= NSWidth(frame)) {
[title drawAtPoint:frame.origin];
return;
}
// Gradient is about twice our line height long.
CGFloat gradient_width = std::min(size.height * 2, NSWidth(frame) / 4);
NSRect solid_part, gradient_part;
NSDivideRect(frame, &gradient_part, &solid_part, gradient_width, NSMaxXEdge);
CGContextRef context = static_cast<CGContextRef>(
[[NSGraphicsContext currentContext] graphicsPort]);
CGContextBeginTransparencyLayerWithRect(context, NSRectToCGRect(frame), 0);
{ // Draw text clipped to frame.
gfx::ScopedNSGraphicsContextSaveGState scoped_state;
[NSBezierPath clipRect:frame];
[title drawAtPoint:frame.origin];
}
NSColor* color = [NSColor blackColor];
NSColor* alpha_color = [color colorWithAlphaComponent:0.0];
base::scoped_nsobject<NSGradient> mask(
[[NSGradient alloc] initWithStartingColor:color endingColor:alpha_color]);
// Draw the gradient mask.
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
[mask drawFromPoint:NSMakePoint(NSMaxX(frame) - gradient_width,
NSMinY(frame))
toPoint:NSMakePoint(NSMaxX(frame),
NSMinY(frame))
options:NSGradientDrawsBeforeStartingLocation];
CGContextEndTransparencyLayer(context);
}
} // namespace
GURL GetFileURLFromDropData(id<NSDraggingInfo> info) {
if ([[info draggingPasteboard] containsURLData]) {
GURL url;
ui::PopulateURLAndTitleFromPasteboard(&url,
NULL,
[info draggingPasteboard],
YES);
if (url.SchemeIs(url::kFileScheme))
return url;
}
return GURL();
}
BOOL IsUnsupportedDropData(Profile* profile, id<NSDraggingInfo> info) {
GURL url = GetFileURLFromDropData(info);
if (!url.is_empty()) {
// If dragging a file, only allow dropping supported file types (that the
// web view can display).
return !IsSupportedFileURL(profile, url);
}
return NO;
}
NSImage* DragImageForBookmark(NSImage* favicon,
const base::string16& title,
CGFloat title_width) {
// If no favicon, use a default.
if (!favicon) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
favicon = rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToNSImage();
}
// If no title, just use icon.
if (title.empty())
return favicon;
NSString* ns_title = base::SysUTF16ToNSString(title);
// Set the look of the title.
NSDictionary* attrs =
[NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:
[NSFont smallSystemFontSize]]
forKey:NSFontAttributeName];
base::scoped_nsobject<NSAttributedString> rich_title(
[[NSAttributedString alloc] initWithString:ns_title attributes:attrs]);
// Set up sizes and locations for rendering.
const CGFloat kIconMargin = 2.0; // Gap between icon and text.
CGFloat text_left = [favicon size].width + kIconMargin;
NSSize drag_image_size = [favicon size];
NSSize text_size = [rich_title size];
CGFloat max_text_width = title_width - text_left;
text_size.width = std::min(text_size.width, max_text_width);
drag_image_size.width = text_left + text_size.width;
// Render the drag image.
NSImage* drag_image =
[[[NSImage alloc] initWithSize:drag_image_size] autorelease];
[drag_image lockFocus];
[favicon drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:0.7];
NSRect target_text_rect = NSMakeRect(text_left, 0,
text_size.width, drag_image_size.height);
DrawTruncatedTitle(rich_title, target_text_rect);
[drag_image unlockFocus];
return drag_image;
}
} // namespace drag_util
|