Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / desktop_capture / mac / desktop_configuration.mm
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
12
13 #include <math.h>
14 #include <algorithm>
15 #include <Cocoa/Cocoa.h>
16
17 #include "webrtc/system_wrappers/interface/logging.h"
18
19 #if !defined(MAC_OS_X_VERSION_10_7) || \
20     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
21
22 @interface NSScreen (LionAPI)
23 - (CGFloat)backingScaleFactor;
24 - (NSRect)convertRectToBacking:(NSRect)aRect;
25 @end
26
27 #endif  // 10.7
28
29 namespace webrtc {
30
31 namespace {
32
33 DesktopRect NSRectToDesktopRect(const NSRect& ns_rect) {
34   return DesktopRect::MakeLTRB(
35       static_cast<int>(floor(ns_rect.origin.x)),
36       static_cast<int>(floor(ns_rect.origin.y)),
37       static_cast<int>(ceil(ns_rect.origin.x + ns_rect.size.width)),
38       static_cast<int>(ceil(ns_rect.origin.y + ns_rect.size.height)));
39 }
40
41 DesktopRect JoinRects(const DesktopRect& a,
42                               const DesktopRect& b) {
43   return DesktopRect::MakeLTRB(
44       std::min(a.left(), b.left()),
45       std::min(a.top(), b.top()),
46       std::max(a.right(), b.right()),
47       std::max(a.bottom(), b.bottom()));
48 }
49
50 // Inverts the position of |rect| from bottom-up coordinates to top-down,
51 // relative to |bounds|.
52 void InvertRectYOrigin(const DesktopRect& bounds,
53                        DesktopRect* rect) {
54   assert(bounds.top() == 0);
55   *rect = DesktopRect::MakeXYWH(
56       rect->left(), bounds.bottom() - rect->bottom(),
57       rect->width(), rect->height());
58 }
59
60 MacDisplayConfiguration GetConfigurationForScreen(NSScreen* screen) {
61   MacDisplayConfiguration display_config;
62
63   // Fetch the NSScreenNumber, which is also the CGDirectDisplayID.
64   NSDictionary* device_description = [screen deviceDescription];
65   display_config.id = static_cast<CGDirectDisplayID>(
66       [[device_description objectForKey:@"NSScreenNumber"] intValue]);
67
68   // Determine the display's logical & physical dimensions.
69   NSRect ns_bounds = [screen frame];
70   display_config.bounds = NSRectToDesktopRect(ns_bounds);
71
72   // If the host is running Mac OS X 10.7+ or later, query the scaling factor
73   // between logical and physical (aka "backing") pixels, otherwise assume 1:1.
74   if ([screen respondsToSelector:@selector(backingScaleFactor)] &&
75       [screen respondsToSelector:@selector(convertRectToBacking:)]) {
76     display_config.dip_to_pixel_scale = [screen backingScaleFactor];
77     NSRect ns_pixel_bounds = [screen convertRectToBacking: ns_bounds];
78     display_config.pixel_bounds = NSRectToDesktopRect(ns_pixel_bounds);
79   } else {
80     display_config.pixel_bounds = display_config.bounds;
81   }
82
83   return display_config;
84 }
85
86 }  // namespace
87
88 MacDisplayConfiguration::MacDisplayConfiguration()
89     : id(0),
90       dip_to_pixel_scale(1.0f) {
91 }
92
93 MacDesktopConfiguration::MacDesktopConfiguration()
94     : dip_to_pixel_scale(1.0f) {
95 }
96
97 MacDesktopConfiguration::~MacDesktopConfiguration() {
98 }
99
100 // static
101 MacDesktopConfiguration MacDesktopConfiguration::GetCurrent(Origin origin) {
102   MacDesktopConfiguration desktop_config;
103
104   NSArray* screens = [NSScreen screens];
105   assert(screens);
106
107   // Iterator over the monitors, adding the primary monitor and monitors whose
108   // DPI match that of the primary monitor.
109   for (NSUInteger i = 0; i < [screens count]; ++i) {
110     MacDisplayConfiguration display_config =
111         GetConfigurationForScreen([screens objectAtIndex: i]);
112
113     if (i == 0)
114       desktop_config.dip_to_pixel_scale = display_config.dip_to_pixel_scale;
115
116     // Cocoa uses bottom-up coordinates, so if the caller wants top-down then
117     // we need to invert the positions of secondary monitors relative to the
118     // primary one (the primary monitor's position is (0,0) in both systems).
119     if (i > 0 && origin == TopLeftOrigin) {
120       InvertRectYOrigin(desktop_config.displays[0].bounds,
121                         &display_config.bounds);
122       // |display_bounds| is density dependent, so we need to convert the
123       // primay monitor's position into the secondary monitor's density context.
124       float scaling_factor = display_config.dip_to_pixel_scale /
125           desktop_config.displays[0].dip_to_pixel_scale;
126       DesktopRect primary_bounds = DesktopRect::MakeLTRB(
127           desktop_config.displays[0].pixel_bounds.left() * scaling_factor,
128           desktop_config.displays[0].pixel_bounds.top() * scaling_factor,
129           desktop_config.displays[0].pixel_bounds.right() * scaling_factor,
130           desktop_config.displays[0].pixel_bounds.bottom() * scaling_factor);
131       InvertRectYOrigin(primary_bounds, &display_config.pixel_bounds);
132     }
133
134     // Add the display to the configuration.
135     desktop_config.displays.push_back(display_config);
136
137     // Update the desktop bounds to account for this display, unless the current
138     // display uses different DPI settings.
139     if (display_config.dip_to_pixel_scale ==
140         desktop_config.dip_to_pixel_scale) {
141       desktop_config.bounds =
142           JoinRects(desktop_config.bounds, display_config.bounds);
143       desktop_config.pixel_bounds =
144           JoinRects(desktop_config.pixel_bounds, display_config.pixel_bounds);
145     }
146   }
147
148   return desktop_config;
149 }
150
151 // For convenience of comparing MacDisplayConfigurations in
152 // MacDesktopConfiguration::Equals.
153 bool operator==(const MacDisplayConfiguration& left,
154                 const MacDisplayConfiguration& right) {
155   return left.id == right.id &&
156       left.bounds.equals(right.bounds) &&
157       left.pixel_bounds.equals(right.pixel_bounds) &&
158       left.dip_to_pixel_scale == right.dip_to_pixel_scale;
159 }
160
161 bool MacDesktopConfiguration::Equals(const MacDesktopConfiguration& other) {
162   return bounds.equals(other.bounds) &&
163       pixel_bounds.equals(other.pixel_bounds) &&
164       dip_to_pixel_scale == other.dip_to_pixel_scale &&
165       displays == other.displays;
166 }
167
168 // Finds the display configuration with the specified id.
169 const MacDisplayConfiguration*
170 MacDesktopConfiguration::FindDisplayConfigurationById(
171     CGDirectDisplayID id) {
172   for (MacDisplayConfigurations::const_iterator it = displays.begin();
173       it != displays.end(); ++it) {
174     if (it->id == id)
175       return &(*it);
176   }
177   return NULL;
178 }
179
180 }  // namespace webrtc