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