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