1 // Copyright (c) 2010 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 "pdf/pdfium/pdfium_range.h"
6 
7 #include "base/check_op.h"
8 #include "base/strings/string_util.h"
9 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h"
10 #include "ui/gfx/geometry/point.h"
11 #include "ui/gfx/geometry/rect.h"
12 
13 namespace chrome_pdf {
14 
15 namespace {
16 
AdjustForBackwardsRange(int * index,int * count)17 void AdjustForBackwardsRange(int* index, int* count) {
18   int& char_index = *index;
19   int& char_count = *count;
20   if (char_count < 0) {
21     char_count *= -1;
22     char_index -= char_count - 1;
23   }
24 }
25 
26 }  // namespace
27 
IsIgnorableCharacter(base::char16 c)28 bool IsIgnorableCharacter(base::char16 c) {
29   return (c == kZeroWidthSpace) || (c == kPDFSoftHyphenMarker);
30 }
31 
PDFiumRange(PDFiumPage * page,int char_index,int char_count)32 PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count)
33     : page_(page), char_index_(char_index), char_count_(char_count) {
34 #if DCHECK_IS_ON()
35   AdjustForBackwardsRange(&char_index, &char_count);
36   DCHECK_LE(char_count, FPDFText_CountChars(page_->GetTextPage()));
37 #endif
38 }
39 
40 PDFiumRange::PDFiumRange(const PDFiumRange& that) = default;
41 
42 PDFiumRange::~PDFiumRange() = default;
43 
SetCharCount(int char_count)44 void PDFiumRange::SetCharCount(int char_count) {
45   char_count_ = char_count;
46 #if DCHECK_IS_ON()
47   int dummy_index = 0;
48   AdjustForBackwardsRange(&dummy_index, &char_count);
49   DCHECK_LE(char_count, FPDFText_CountChars(page_->GetTextPage()));
50 #endif
51 
52   cached_screen_rects_point_ = gfx::Point();
53   cached_screen_rects_zoom_ = 0;
54 }
55 
GetScreenRects(const gfx::Point & point,double zoom,PageOrientation orientation) const56 const std::vector<gfx::Rect>& PDFiumRange::GetScreenRects(
57     const gfx::Point& point,
58     double zoom,
59     PageOrientation orientation) const {
60   if (point == cached_screen_rects_point_ &&
61       zoom == cached_screen_rects_zoom_) {
62     return cached_screen_rects_;
63   }
64 
65   cached_screen_rects_.clear();
66   cached_screen_rects_point_ = point;
67   cached_screen_rects_zoom_ = zoom;
68 
69   int char_index = char_index_;
70   int char_count = char_count_;
71   if (char_count == 0)
72     return cached_screen_rects_;
73 
74   AdjustForBackwardsRange(&char_index, &char_count);
75   DCHECK_GE(char_index, 0) << " start: " << char_index_
76                            << " count: " << char_count_;
77   DCHECK_LT(char_index, FPDFText_CountChars(page_->GetTextPage()))
78       << " start: " << char_index_ << " count: " << char_count_;
79 
80   int count = FPDFText_CountRects(page_->GetTextPage(), char_index, char_count);
81   for (int i = 0; i < count; ++i) {
82     double left;
83     double top;
84     double right;
85     double bottom;
86     FPDFText_GetRect(page_->GetTextPage(), i, &left, &top, &right, &bottom);
87     gfx::Rect rect =
88         page_->PageToScreen(point, zoom, left, top, right, bottom, orientation);
89     if (rect.IsEmpty())
90       continue;
91     cached_screen_rects_.push_back(rect);
92   }
93 
94   return cached_screen_rects_;
95 }
96 
GetText() const97 base::string16 PDFiumRange::GetText() const {
98   int index = char_index_;
99   int count = char_count_;
100   base::string16 rv;
101   if (count == 0)
102     return rv;
103 
104   AdjustForBackwardsRange(&index, &count);
105   if (count > 0) {
106     PDFiumAPIStringBufferAdapter<base::string16> api_string_adapter(&rv, count,
107                                                                     false);
108     unsigned short* data =
109         reinterpret_cast<unsigned short*>(api_string_adapter.GetData());
110     int written = FPDFText_GetText(page_->GetTextPage(), index, count, data);
111     api_string_adapter.Close(written);
112   }
113 
114   base::EraseIf(rv, [](base::char16 c) { return IsIgnorableCharacter(c); });
115 
116   return rv;
117 }
118 
119 }  // namespace chrome_pdf
120