pdf_web_contents_helper.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. #include "components/pdf/browser/pdf_web_contents_helper.h"
  5. #include <utility>
  6. #include "base/memory/ptr_util.h"
  7. #include "base/notreached.h"
  8. #include "components/pdf/browser/pdf_web_contents_helper_client.h"
  9. #include "content/public/browser/render_widget_host.h"
  10. #include "content/public/browser/render_widget_host_view.h"
  11. #include "content/public/common/referrer_type_converters.h"
  12. #include "ui/base/pointer/touch_editing_controller.h"
  13. #include "ui/base/ui_base_types.h"
  14. #include "ui/gfx/geometry/point_conversions.h"
  15. #include "ui/gfx/geometry/point_f.h"
  16. namespace pdf {
  17. // static
  18. void PDFWebContentsHelper::CreateForWebContentsWithClient(
  19. content::WebContents* contents,
  20. std::unique_ptr<PDFWebContentsHelperClient> client) {
  21. if (FromWebContents(contents))
  22. return;
  23. contents->SetUserData(
  24. UserDataKey(),
  25. base::WrapUnique(new PDFWebContentsHelper(contents, std::move(client))));
  26. }
  27. // static
  28. void PDFWebContentsHelper::BindPdfService(
  29. mojo::PendingAssociatedReceiver<mojom::PdfService> pdf_service,
  30. content::RenderFrameHost* rfh) {
  31. auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
  32. if (!web_contents)
  33. return;
  34. auto* pdf_helper = PDFWebContentsHelper::FromWebContents(web_contents);
  35. if (!pdf_helper)
  36. return;
  37. pdf_helper->pdf_service_receivers_.Bind(rfh, std::move(pdf_service));
  38. }
  39. PDFWebContentsHelper::PDFWebContentsHelper(
  40. content::WebContents* web_contents,
  41. std::unique_ptr<PDFWebContentsHelperClient> client)
  42. : content::WebContentsUserData<PDFWebContentsHelper>(*web_contents),
  43. pdf_service_receivers_(web_contents, this),
  44. client_(std::move(client)) {}
  45. PDFWebContentsHelper::~PDFWebContentsHelper() {
  46. if (pdf_rwh_)
  47. pdf_rwh_->RemoveObserver(this);
  48. if (!touch_selection_controller_client_manager_)
  49. return;
  50. // PDFWebContentsHelperTest overrides TouchSelectionControllerClientManager
  51. // to mock it and GetTouchSelectionController() returns nullptr in that case.
  52. // This check prevents the tests from failing in that condition.
  53. ui::TouchSelectionController* touch_selection_controller =
  54. touch_selection_controller_client_manager_->GetTouchSelectionController();
  55. if (touch_selection_controller)
  56. touch_selection_controller->HideAndDisallowShowingAutomatically();
  57. touch_selection_controller_client_manager_->InvalidateClient(this);
  58. touch_selection_controller_client_manager_->RemoveObserver(this);
  59. }
  60. void PDFWebContentsHelper::SetListener(
  61. mojo::PendingRemote<mojom::PdfListener> listener) {
  62. remote_pdf_client_.reset();
  63. remote_pdf_client_.Bind(std::move(listener));
  64. if (pdf_rwh_)
  65. pdf_rwh_->RemoveObserver(this);
  66. pdf_rwh_ = client_->FindPdfFrame(&GetWebContents())->GetRenderWidgetHost();
  67. pdf_rwh_->AddObserver(this);
  68. }
  69. gfx::PointF PDFWebContentsHelper::ConvertHelper(const gfx::PointF& point_f,
  70. float scale) {
  71. if (!pdf_rwh_)
  72. return point_f;
  73. content::RenderWidgetHostView* view = pdf_rwh_->GetView();
  74. if (!view)
  75. return point_f;
  76. gfx::Vector2dF offset =
  77. view->TransformPointToRootCoordSpaceF(gfx::PointF()).OffsetFromOrigin();
  78. offset.Scale(scale);
  79. return point_f + offset;
  80. }
  81. gfx::PointF PDFWebContentsHelper::ConvertFromRoot(const gfx::PointF& point_f) {
  82. return ConvertHelper(point_f, -1.f);
  83. }
  84. gfx::PointF PDFWebContentsHelper::ConvertToRoot(const gfx::PointF& point_f) {
  85. return ConvertHelper(point_f, +1.f);
  86. }
  87. void PDFWebContentsHelper::SelectionChanged(const gfx::PointF& left,
  88. int32_t left_height,
  89. const gfx::PointF& right,
  90. int32_t right_height) {
  91. selection_left_ = left;
  92. selection_left_height_ = left_height;
  93. selection_right_ = right;
  94. selection_right_height_ = right_height;
  95. DidScroll();
  96. }
  97. void PDFWebContentsHelper::SetPluginCanSave(bool can_save) {
  98. client_->SetPluginCanSave(&GetWebContents(), can_save);
  99. }
  100. void PDFWebContentsHelper::DidScroll() {
  101. if (!touch_selection_controller_client_manager_)
  102. InitTouchSelectionClientManager();
  103. if (touch_selection_controller_client_manager_) {
  104. gfx::SelectionBound start;
  105. gfx::SelectionBound end;
  106. start.SetEdgeStart(ConvertToRoot(selection_left_));
  107. start.SetEdgeEnd(ConvertToRoot(gfx::PointF(
  108. selection_left_.x(), selection_left_.y() + selection_left_height_)));
  109. end.SetEdgeStart(ConvertToRoot(selection_right_));
  110. end.SetEdgeEnd(ConvertToRoot(gfx::PointF(
  111. selection_right_.x(), selection_right_.y() + selection_right_height_)));
  112. // TouchSelectionControllerClientAura needs these visible edges of selection
  113. // to show the quick menu and context menu. Set the visible edges by the
  114. // edges of |start| and |end|.
  115. start.SetVisibleEdge(start.edge_start(), start.edge_end());
  116. end.SetVisibleEdge(end.edge_start(), end.edge_end());
  117. // Don't do left/right comparison after setting type.
  118. // TODO(wjmaclean): When PDFium supports editing, we'll need to detect
  119. // start == end as *either* no selection, or an insertion point.
  120. has_selection_ = start != end;
  121. start.set_visible(has_selection_);
  122. end.set_visible(has_selection_);
  123. start.set_type(has_selection_ ? gfx::SelectionBound::LEFT
  124. : gfx::SelectionBound::EMPTY);
  125. end.set_type(has_selection_ ? gfx::SelectionBound::RIGHT
  126. : gfx::SelectionBound::EMPTY);
  127. touch_selection_controller_client_manager_->UpdateClientSelectionBounds(
  128. start, end, this, this);
  129. }
  130. }
  131. void PDFWebContentsHelper::RenderWidgetHostDestroyed(
  132. content::RenderWidgetHost* widget_host) {
  133. if (pdf_rwh_ == widget_host)
  134. pdf_rwh_ = nullptr;
  135. }
  136. bool PDFWebContentsHelper::SupportsAnimation() const {
  137. return false;
  138. }
  139. void PDFWebContentsHelper::MoveCaret(const gfx::PointF& position) {
  140. if (!remote_pdf_client_)
  141. return;
  142. remote_pdf_client_->SetCaretPosition(ConvertFromRoot(position));
  143. }
  144. void PDFWebContentsHelper::MoveRangeSelectionExtent(const gfx::PointF& extent) {
  145. if (!remote_pdf_client_)
  146. return;
  147. remote_pdf_client_->MoveRangeSelectionExtent(ConvertFromRoot(extent));
  148. }
  149. void PDFWebContentsHelper::SelectBetweenCoordinates(const gfx::PointF& base,
  150. const gfx::PointF& extent) {
  151. if (!remote_pdf_client_)
  152. return;
  153. remote_pdf_client_->SetSelectionBounds(ConvertFromRoot(base),
  154. ConvertFromRoot(extent));
  155. }
  156. void PDFWebContentsHelper::OnSelectionEvent(ui::SelectionEventType event) {
  157. // Should be handled by `TouchSelectionControllerClientAura`.
  158. NOTREACHED();
  159. }
  160. void PDFWebContentsHelper::OnDragUpdate(
  161. const ui::TouchSelectionDraggable::Type type,
  162. const gfx::PointF& position) {
  163. // Should be handled by `TouchSelectionControllerClientAura`.
  164. NOTREACHED();
  165. }
  166. std::unique_ptr<ui::TouchHandleDrawable>
  167. PDFWebContentsHelper::CreateDrawable() {
  168. // We can return null here, as the manager will look after this.
  169. return nullptr;
  170. }
  171. void PDFWebContentsHelper::OnManagerWillDestroy(
  172. content::TouchSelectionControllerClientManager* manager) {
  173. DCHECK_EQ(touch_selection_controller_client_manager_, manager);
  174. manager->RemoveObserver(this);
  175. touch_selection_controller_client_manager_ = nullptr;
  176. }
  177. bool PDFWebContentsHelper::IsCommandIdEnabled(int command_id) const {
  178. // TODO(wjmaclean|dsinclair): Make PDFium send readability information in the
  179. // selection changed message?
  180. bool readable = true;
  181. switch (command_id) {
  182. case ui::TouchEditable::kCopy:
  183. return readable && has_selection_;
  184. // TODO(wjmaclean): add logic for cut/paste as the information required
  185. // from PDFium becomes available.
  186. }
  187. return false;
  188. }
  189. void PDFWebContentsHelper::ExecuteCommand(int command_id, int event_flags) {
  190. // TODO(wjmaclean, dsinclair): Need to communicate to PDFium to accept
  191. // cut/paste commands.
  192. switch (command_id) {
  193. case ui::TouchEditable::kCopy:
  194. GetWebContents().Copy();
  195. break;
  196. }
  197. }
  198. void PDFWebContentsHelper::RunContextMenu() {
  199. content::RenderFrameHost* focused_frame = GetWebContents().GetFocusedFrame();
  200. if (!focused_frame)
  201. return;
  202. content::RenderWidgetHost* widget = focused_frame->GetRenderWidgetHost();
  203. if (!widget || !widget->GetView())
  204. return;
  205. if (!touch_selection_controller_client_manager_)
  206. InitTouchSelectionClientManager();
  207. if (!touch_selection_controller_client_manager_)
  208. return;
  209. ui::TouchSelectionController* touch_selection_controller =
  210. touch_selection_controller_client_manager_->GetTouchSelectionController();
  211. gfx::RectF anchor_rect =
  212. touch_selection_controller->GetVisibleRectBetweenBounds();
  213. gfx::PointF anchor_point =
  214. gfx::PointF(anchor_rect.CenterPoint().x(), anchor_rect.y());
  215. gfx::PointF origin =
  216. widget->GetView()->TransformPointToRootCoordSpaceF(gfx::PointF());
  217. anchor_point.Offset(-origin.x(), -origin.y());
  218. widget->ShowContextMenuAtPoint(gfx::ToRoundedPoint(anchor_point),
  219. ui::MENU_SOURCE_TOUCH_EDIT_MENU);
  220. // Hide selection handles after getting rect-between-bounds from touch
  221. // selection controller; otherwise, rect would be empty and the above
  222. // calculations would be invalid.
  223. touch_selection_controller->HideAndDisallowShowingAutomatically();
  224. }
  225. bool PDFWebContentsHelper::ShouldShowQuickMenu() {
  226. return false;
  227. }
  228. std::u16string PDFWebContentsHelper::GetSelectedText() {
  229. return std::u16string();
  230. }
  231. void PDFWebContentsHelper::InitTouchSelectionClientManager() {
  232. content::RenderWidgetHostView* view =
  233. GetWebContents().GetRenderWidgetHostView();
  234. if (!view)
  235. return;
  236. touch_selection_controller_client_manager_ =
  237. view->GetTouchSelectionControllerClientManager();
  238. if (!touch_selection_controller_client_manager_)
  239. return;
  240. touch_selection_controller_client_manager_->AddObserver(this);
  241. }
  242. void PDFWebContentsHelper::HasUnsupportedFeature() {
  243. client_->OnPDFHasUnsupportedFeature(&GetWebContents());
  244. }
  245. void PDFWebContentsHelper::SaveUrlAs(const GURL& url,
  246. network::mojom::ReferrerPolicy policy) {
  247. client_->OnSaveURL(&GetWebContents());
  248. content::RenderFrameHost* rfh = GetWebContents().GetOuterWebContentsFrame();
  249. if (!rfh)
  250. return;
  251. content::Referrer referrer(url, policy);
  252. referrer = content::Referrer::SanitizeForRequest(url, referrer);
  253. GetWebContents().SaveFrame(url, referrer, rfh);
  254. }
  255. void PDFWebContentsHelper::UpdateContentRestrictions(
  256. int32_t content_restrictions) {
  257. client_->UpdateContentRestrictions(&GetWebContents(), content_restrictions);
  258. }
  259. WEB_CONTENTS_USER_DATA_KEY_IMPL(PDFWebContentsHelper);
  260. } // namespace pdf