• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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.
4 
5 #include "content/renderer/geolocation_dispatcher.h"
6 
7 #include "content/common/geolocation_messages.h"
8 #include "content/renderer/render_view_impl.h"
9 #include "third_party/WebKit/public/platform/WebString.h"
10 #include "third_party/WebKit/public/web/WebGeolocationPermissionRequest.h"
11 #include "third_party/WebKit/public/web/WebGeolocationPermissionRequestManager.h"
12 #include "third_party/WebKit/public/web/WebGeolocationClient.h"
13 #include "third_party/WebKit/public/web/WebGeolocationPosition.h"
14 #include "third_party/WebKit/public/web/WebGeolocationError.h"
15 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
16 
17 using blink::WebGeolocationController;
18 using blink::WebGeolocationError;
19 using blink::WebGeolocationPermissionRequest;
20 using blink::WebGeolocationPermissionRequestManager;
21 using blink::WebGeolocationPosition;
22 
23 namespace content {
24 
GeolocationDispatcher(RenderFrame * render_frame)25 GeolocationDispatcher::GeolocationDispatcher(RenderFrame* render_frame)
26     : RenderFrameObserver(render_frame),
27       pending_permissions_(new WebGeolocationPermissionRequestManager()),
28       enable_high_accuracy_(false),
29       updating_(false) {
30 }
31 
~GeolocationDispatcher()32 GeolocationDispatcher::~GeolocationDispatcher() {}
33 
OnMessageReceived(const IPC::Message & message)34 bool GeolocationDispatcher::OnMessageReceived(const IPC::Message& message) {
35   bool handled = true;
36   IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcher, message)
37     IPC_MESSAGE_HANDLER(GeolocationMsg_PermissionSet, OnPermissionSet)
38     IPC_MESSAGE_HANDLER(GeolocationMsg_PositionUpdated, OnPositionUpdated)
39     IPC_MESSAGE_UNHANDLED(handled = false)
40   IPC_END_MESSAGE_MAP()
41   return handled;
42 }
43 
startUpdating()44 void GeolocationDispatcher::startUpdating() {
45   GURL url;
46   Send(new GeolocationHostMsg_StartUpdating(
47       routing_id(), url, enable_high_accuracy_));
48   updating_ = true;
49 }
50 
stopUpdating()51 void GeolocationDispatcher::stopUpdating() {
52   Send(new GeolocationHostMsg_StopUpdating(routing_id()));
53   updating_ = false;
54 }
55 
setEnableHighAccuracy(bool enable_high_accuracy)56 void GeolocationDispatcher::setEnableHighAccuracy(bool enable_high_accuracy) {
57   // GeolocationController calls setEnableHighAccuracy(true) before
58   // startUpdating in response to the first high-accuracy Geolocation
59   // subscription. When the last high-accuracy Geolocation unsubscribes
60   // it calls setEnableHighAccuracy(false) after stopUpdating.
61   bool has_changed = enable_high_accuracy_ != enable_high_accuracy;
62   enable_high_accuracy_ = enable_high_accuracy;
63   // We have a different accuracy requirement. Request browser to update.
64   if (updating_ && has_changed)
65     startUpdating();
66 }
67 
setController(WebGeolocationController * controller)68 void GeolocationDispatcher::setController(
69     WebGeolocationController* controller) {
70   controller_.reset(controller);
71 }
72 
lastPosition(WebGeolocationPosition &)73 bool GeolocationDispatcher::lastPosition(WebGeolocationPosition&) {
74   // The latest position is stored in the browser, not the renderer, so we
75   // would have to fetch it synchronously to give a good value here.  The
76   // WebCore::GeolocationController already caches the last position it
77   // receives, so there is not much benefit to more position caching here.
78   return false;
79 }
80 
81 // TODO(jknotten): Change the messages to use a security origin, so no
82 // conversion is necessary.
requestPermission(const WebGeolocationPermissionRequest & permissionRequest)83 void GeolocationDispatcher::requestPermission(
84     const WebGeolocationPermissionRequest& permissionRequest) {
85   int bridge_id = pending_permissions_->add(permissionRequest);
86   base::string16 origin = permissionRequest.securityOrigin().toString();
87   Send(new GeolocationHostMsg_RequestPermission(
88       routing_id(), bridge_id, GURL(origin),
89       blink::WebUserGestureIndicator::isProcessingUserGesture()));
90 }
91 
92 // TODO(jknotten): Change the messages to use a security origin, so no
93 // conversion is necessary.
cancelPermissionRequest(const WebGeolocationPermissionRequest & permissionRequest)94 void GeolocationDispatcher::cancelPermissionRequest(
95     const WebGeolocationPermissionRequest& permissionRequest) {
96   int bridge_id;
97   if (!pending_permissions_->remove(permissionRequest, bridge_id))
98     return;
99   base::string16 origin = permissionRequest.securityOrigin().toString();
100   Send(new GeolocationHostMsg_CancelPermissionRequest(
101       routing_id(), bridge_id, GURL(origin)));
102 }
103 
104 // Permission for using geolocation has been set.
OnPermissionSet(int bridge_id,bool is_allowed)105 void GeolocationDispatcher::OnPermissionSet(int bridge_id, bool is_allowed) {
106   WebGeolocationPermissionRequest permissionRequest;
107   if (!pending_permissions_->remove(bridge_id, permissionRequest))
108     return;
109   permissionRequest.setIsAllowed(is_allowed);
110 }
111 
112 // We have an updated geolocation position or error code.
OnPositionUpdated(const Geoposition & geoposition)113 void GeolocationDispatcher::OnPositionUpdated(
114     const Geoposition& geoposition) {
115   // It is possible for the browser process to have queued an update message
116   // before receiving the stop updating message.
117   if (!updating_)
118     return;
119 
120   if (geoposition.Validate()) {
121     controller_->positionChanged(
122         WebGeolocationPosition(
123             geoposition.timestamp.ToDoubleT(),
124             geoposition.latitude, geoposition.longitude,
125             geoposition.accuracy,
126             // Lowest point on land is at approximately -400 meters.
127             geoposition.altitude > -10000.,
128             geoposition.altitude,
129             geoposition.altitude_accuracy >= 0.,
130             geoposition.altitude_accuracy,
131             geoposition.heading >= 0. && geoposition.heading <= 360.,
132             geoposition.heading,
133             geoposition.speed >= 0.,
134             geoposition.speed));
135   } else {
136     WebGeolocationError::Error code;
137     switch (geoposition.error_code) {
138       case Geoposition::ERROR_CODE_PERMISSION_DENIED:
139         code = WebGeolocationError::ErrorPermissionDenied;
140         break;
141       case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
142         code = WebGeolocationError::ErrorPositionUnavailable;
143         break;
144       default:
145         NOTREACHED() << geoposition.error_code;
146         return;
147     }
148     controller_->errorOccurred(
149         WebGeolocationError(
150             code, blink::WebString::fromUTF8(geoposition.error_message)));
151   }
152 }
153 
154 }  // namespace content
155