Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "pdf/pdfium/pdfium_page.h" | 5 #include "pdf/pdfium/pdfium_page.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <memory> | 11 #include <memory> |
| 12 #include <utility> | 12 #include <utility> |
| 13 | 13 |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/numerics/safe_math.h" | 15 #include "base/numerics/safe_math.h" |
| 16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 19 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" | 19 #include "pdf/pdfium/pdfium_api_string_buffer_adapter.h" |
| 20 #include "pdf/pdfium/pdfium_engine.h" | 20 #include "pdf/pdfium/pdfium_engine.h" |
| 21 #include "printing/units.h" | 21 #include "printing/units.h" |
| 22 | 22 |
| 23 // Used when doing hit detection. | |
| 24 #define kTolerance 20.0 | |
| 25 | |
| 26 using printing::ConvertUnitDouble; | 23 using printing::ConvertUnitDouble; |
| 27 using printing::kPointsPerInch; | 24 using printing::kPointsPerInch; |
| 28 using printing::kPixelsPerInch; | 25 using printing::kPixelsPerInch; |
| 29 | 26 |
| 30 namespace { | 27 namespace { |
| 31 | 28 |
| 32 pp::FloatRect FloatPageRectToPixelRect(FPDF_PAGE page, | 29 pp::FloatRect FloatPageRectToPixelRect(FPDF_PAGE page, |
| 33 const pp::FloatRect& input) { | 30 const pp::FloatRect& input) { |
| 34 int output_width = FPDF_GetPageWidth(page); | 31 int output_width = FPDF_GetPageWidth(page); |
| 35 int output_height = FPDF_GetPageHeight(page); | 32 int output_height = FPDF_GetPageHeight(page); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 int* form_type, | 237 int* form_type, |
| 241 LinkTarget* target) { | 238 LinkTarget* target) { |
| 242 if (!available_) | 239 if (!available_) |
| 243 return NONSELECTABLE_AREA; | 240 return NONSELECTABLE_AREA; |
| 244 pp::Point point2 = point - rect_.point(); | 241 pp::Point point2 = point - rect_.point(); |
| 245 double new_x; | 242 double new_x; |
| 246 double new_y; | 243 double new_y; |
| 247 FPDF_DeviceToPage(GetPage(), 0, 0, rect_.width(), rect_.height(), rotation, | 244 FPDF_DeviceToPage(GetPage(), 0, 0, rect_.width(), rect_.height(), rotation, |
| 248 point2.x(), point2.y(), &new_x, &new_y); | 245 point2.x(), point2.y(), &new_x, &new_y); |
| 249 | 246 |
| 247 // hit detection tolerance, in points. | |
| 248 constexpr double kTolerance = 20.0; | |
| 250 int rv = FPDFText_GetCharIndexAtPos(GetTextPage(), new_x, new_y, kTolerance, | 249 int rv = FPDFText_GetCharIndexAtPos(GetTextPage(), new_x, new_y, kTolerance, |
| 251 kTolerance); | 250 kTolerance); |
| 252 *char_index = rv; | 251 *char_index = rv; |
| 253 | 252 |
| 254 FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), new_x, new_y); | 253 FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), new_x, new_y); |
| 255 int control = | 254 int control = |
| 256 FPDFPage_HasFormFieldAtPoint(engine_->form(), GetPage(), new_x, new_y); | 255 FPDFPage_HasFormFieldAtPoint(engine_->form(), GetPage(), new_x, new_y); |
| 257 | 256 |
| 258 // If there is a control and link at the same point, figure out their z-order | 257 // If there is a control and link at the same point, figure out their z-order |
| 259 // to determine which is on top. | 258 // to determine which is on top. |
| 260 if (link && control > FPDF_FORMFIELD_UNKNOWN) { | 259 if (link && control > FPDF_FORMFIELD_UNKNOWN) { |
| 261 int control_z_order = FPDFPage_FormFieldZOrderAtPoint( | 260 int control_z_order = FPDFPage_FormFieldZOrderAtPoint( |
| 262 engine_->form(), GetPage(), new_x, new_y); | 261 engine_->form(), GetPage(), new_x, new_y); |
| 263 int link_z_order = FPDFLink_GetLinkZOrderAtPoint(GetPage(), new_x, new_y); | 262 int link_z_order = FPDFLink_GetLinkZOrderAtPoint(GetPage(), new_x, new_y); |
| 264 DCHECK_NE(control_z_order, link_z_order); | 263 DCHECK_NE(control_z_order, link_z_order); |
| 265 if (control_z_order > link_z_order) { | 264 if (control_z_order > link_z_order) { |
| 266 *form_type = control; | 265 *form_type = control; |
| 267 return FormTypeToArea(*form_type); | 266 return FormTypeToArea(*form_type); |
| 268 } | 267 } |
| 269 | 268 |
| 270 // We don't handle all possible link types of the PDF. For example, | 269 // We don't handle all possible link types of the PDF. For example, |
| 271 // launch actions, cross-document links, etc. | 270 // launch actions, cross-document links, etc. |
| 272 // In that case, GetLinkTarget() will return NONSELECTABLE_AREA | 271 // In that case, GetLinkTarget() will return NONSELECTABLE_AREA |
| 273 // and we should proceed with area detection. | 272 // and we should proceed with area detection. |
| 274 PDFiumPage::Area area = GetLinkTarget(link, target); | 273 Area area = GetLinkTarget(link, target); |
| 275 if (area != PDFiumPage::NONSELECTABLE_AREA) | 274 if (area != NONSELECTABLE_AREA) |
| 276 return area; | 275 return area; |
| 277 } else if (link) { | 276 } else if (link) { |
| 278 // We don't handle all possible link types of the PDF. For example, | 277 // We don't handle all possible link types of the PDF. For example, |
| 279 // launch actions, cross-document links, etc. | 278 // launch actions, cross-document links, etc. |
| 280 // See identical block above. | 279 // See identical block above. |
| 281 PDFiumPage::Area area = GetLinkTarget(link, target); | 280 Area area = GetLinkTarget(link, target); |
| 282 if (area != PDFiumPage::NONSELECTABLE_AREA) | 281 if (area != NONSELECTABLE_AREA) |
| 283 return area; | 282 return area; |
| 284 } else if (control > FPDF_FORMFIELD_UNKNOWN) { | 283 } else if (control > FPDF_FORMFIELD_UNKNOWN) { |
| 285 *form_type = control; | 284 *form_type = control; |
| 286 return FormTypeToArea(*form_type); | 285 return FormTypeToArea(*form_type); |
| 287 } | 286 } |
| 288 | 287 |
| 289 if (rv < 0) | 288 if (rv < 0) |
| 290 return NONSELECTABLE_AREA; | 289 return NONSELECTABLE_AREA; |
| 291 | 290 |
| 292 return GetLink(*char_index, target) != -1 ? WEBLINK_AREA : TEXT_AREA; | 291 return GetLink(*char_index, target) != -1 ? WEBLINK_AREA : TEXT_AREA; |
| 293 } | 292 } |
| 294 | 293 |
| 295 // static | 294 // static |
| 296 PDFiumPage::Area PDFiumPage::FormTypeToArea(int form_type) { | 295 PDFiumPage::Area PDFiumPage::FormTypeToArea(int form_type) { |
| 297 switch (form_type) { | 296 switch (form_type) { |
| 298 case FPDF_FORMFIELD_COMBOBOX: | 297 case FPDF_FORMFIELD_COMBOBOX: |
| 299 case FPDF_FORMFIELD_TEXTFIELD: | 298 case FPDF_FORMFIELD_TEXTFIELD: |
| 300 return PDFiumPage::FORM_TEXT_AREA; | 299 return FORM_TEXT_AREA; |
| 301 default: | 300 default: |
| 302 return PDFiumPage::NONSELECTABLE_AREA; | 301 return NONSELECTABLE_AREA; |
| 303 } | 302 } |
| 304 } | 303 } |
| 305 | 304 |
| 306 base::char16 PDFiumPage::GetCharAtIndex(int index) { | 305 base::char16 PDFiumPage::GetCharAtIndex(int index) { |
| 307 if (!available_) | 306 if (!available_) |
| 308 return L'\0'; | 307 return L'\0'; |
| 309 return static_cast<base::char16>(FPDFText_GetUnicode(GetTextPage(), index)); | 308 return static_cast<base::char16>(FPDFText_GetUnicode(GetTextPage(), index)); |
| 310 } | 309 } |
| 311 | 310 |
| 312 int PDFiumPage::GetCharCount() { | 311 int PDFiumPage::GetCharCount() { |
| 313 if (!available_) | 312 if (!available_) |
| 314 return 0; | 313 return 0; |
| 315 return FPDFText_CountChars(GetTextPage()); | 314 return FPDFText_CountChars(GetTextPage()); |
| 316 } | 315 } |
| 317 | 316 |
| 318 PDFiumPage::Area PDFiumPage::GetLinkTarget( | 317 PDFiumPage::Area PDFiumPage::GetLinkTarget(FPDF_LINK link, |
| 319 FPDF_LINK link, | 318 LinkTarget* target) const { |
| 320 PDFiumPage::LinkTarget* target) const { | |
| 321 FPDF_DEST dest = FPDFLink_GetDest(engine_->doc(), link); | 319 FPDF_DEST dest = FPDFLink_GetDest(engine_->doc(), link); |
| 322 if (dest) | 320 if (dest) |
| 323 return GetDestinationTarget(dest, target); | 321 return GetDestinationTarget(dest, target); |
| 324 | 322 |
| 325 FPDF_ACTION action = FPDFLink_GetAction(link); | 323 FPDF_ACTION action = FPDFLink_GetAction(link); |
| 326 if (action) { | 324 if (!action) |
| 327 // TODO(gene): We don't support PDFACTION_REMOTEGOTO and | 325 return NONSELECTABLE_AREA; |
| 328 // PDFACTION_LAUNCH at the moment. | 326 |
| 329 switch (FPDFAction_GetType(action)) { | 327 switch (FPDFAction_GetType(action)) { |
| 330 case PDFACTION_GOTO: { | 328 case PDFACTION_GOTO: { |
| 331 FPDF_DEST dest = FPDFAction_GetDest(engine_->doc(), action); | 329 FPDF_DEST dest = FPDFAction_GetDest(engine_->doc(), action); |
| 332 if (dest) | 330 if (dest) |
| 333 return GetDestinationTarget(dest, target); | 331 return GetDestinationTarget(dest, target); |
| 334 // TODO(gene): We don't fully support all types of the in-document | 332 // TODO(thestig): We don't fully support all types of the in-document |
| 335 // links. Need to implement that. There is a bug to track that: | 333 // links. Need to implement that. There is a bug to track that: |
| 336 // http://code.google.com/p/chromium/issues/detail?id=55776 | 334 // https://crbug.com/55776 |
| 337 break; | 335 return NONSELECTABLE_AREA; |
| 338 } | |
| 339 case PDFACTION_URI: { | |
| 340 if (target) { | |
| 341 size_t buffer_size = | |
| 342 FPDFAction_GetURIPath(engine_->doc(), action, nullptr, 0); | |
| 343 if (buffer_size > 0) { | |
| 344 PDFiumAPIStringBufferAdapter<std::string> api_string_adapter( | |
| 345 &target->url, buffer_size, true); | |
| 346 void* data = api_string_adapter.GetData(); | |
| 347 size_t bytes_written = FPDFAction_GetURIPath(engine_->doc(), action, | |
| 348 data, buffer_size); | |
| 349 api_string_adapter.Close(bytes_written); | |
| 350 } | |
| 351 } | |
| 352 return WEBLINK_AREA; | |
| 353 } | |
| 354 } | 336 } |
| 337 case PDFACTION_URI: | |
| 338 return GetURITarget(action, target); | |
| 339 // TODO(thestig): Support remaining types for https://crbug.com/55776 | |
| 340 case PDFACTION_LAUNCH: | |
| 341 case PDFACTION_REMOTEGOTO: | |
| 342 default: | |
| 343 return NONSELECTABLE_AREA; | |
| 355 } | 344 } |
| 356 | |
| 357 return NONSELECTABLE_AREA; | |
| 358 } | 345 } |
| 359 | 346 |
| 360 PDFiumPage::Area PDFiumPage::GetDestinationTarget( | 347 PDFiumPage::Area PDFiumPage::GetDestinationTarget(FPDF_DEST destination, |
| 361 FPDF_DEST destination, | 348 LinkTarget* target) const { |
| 362 PDFiumPage::LinkTarget* target) const { | |
| 363 if (target) | 349 if (target) |
| 364 target->page = FPDFDest_GetPageIndex(engine_->doc(), destination); | 350 target->page = FPDFDest_GetPageIndex(engine_->doc(), destination); |
| 365 return DOCLINK_AREA; | 351 return DOCLINK_AREA; |
| 366 } | 352 } |
| 367 | 353 |
| 368 int PDFiumPage::GetLink(int char_index, PDFiumPage::LinkTarget* target) { | 354 PDFiumPage::Area PDFiumPage::GetURITarget(FPDF_ACTION uri_action, |
| 355 LinkTarget* target) const { | |
| 356 if (target) { | |
|
dsinclair
2017/06/26 19:44:38
if (!target)
return WEBLINK_AREA;
Lei Zhang
2017/06/26 20:57:59
I wrote it this way because:
- Early returns ends
| |
| 357 size_t buffer_size = | |
| 358 FPDFAction_GetURIPath(engine_->doc(), uri_action, nullptr, 0); | |
| 359 if (buffer_size > 0) { | |
|
dsinclair
2017/06/26 19:44:39
ditto early exit?
| |
| 360 PDFiumAPIStringBufferAdapter<std::string> api_string_adapter( | |
| 361 &target->url, buffer_size, true); | |
| 362 void* data = api_string_adapter.GetData(); | |
| 363 size_t bytes_written = | |
| 364 FPDFAction_GetURIPath(engine_->doc(), uri_action, data, buffer_size); | |
| 365 api_string_adapter.Close(bytes_written); | |
| 366 } | |
| 367 } | |
| 368 return WEBLINK_AREA; | |
| 369 } | |
| 370 | |
| 371 int PDFiumPage::GetLink(int char_index, LinkTarget* target) { | |
| 369 if (!available_) | 372 if (!available_) |
| 370 return -1; | 373 return -1; |
| 371 | 374 |
| 372 CalculateLinks(); | 375 CalculateLinks(); |
| 373 | 376 |
| 374 // Get the bounding box of the rect again, since it might have moved because | 377 // Get the bounding box of the rect again, since it might have moved because |
| 375 // of the tolerance above. | 378 // of the tolerance above. |
| 376 double left, right, bottom, top; | 379 double left, right, bottom, top; |
| 377 FPDFText_GetCharBox(GetTextPage(), char_index, &left, &right, &bottom, &top); | 380 FPDFText_GetCharBox(GetTextPage(), char_index, &left, &right, &bottom, &top); |
| 378 | 381 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 533 page_->loading_count_--; | 536 page_->loading_count_--; |
| 534 } | 537 } |
| 535 | 538 |
| 536 PDFiumPage::Link::Link() = default; | 539 PDFiumPage::Link::Link() = default; |
| 537 | 540 |
| 538 PDFiumPage::Link::Link(const Link& that) = default; | 541 PDFiumPage::Link::Link(const Link& that) = default; |
| 539 | 542 |
| 540 PDFiumPage::Link::~Link() = default; | 543 PDFiumPage::Link::~Link() = default; |
| 541 | 544 |
| 542 } // namespace chrome_pdf | 545 } // namespace chrome_pdf |
| OLD | NEW |