0

Add CallPDFiumWideStringBufferApi() helper.

Most PDFiumAPIStringBufferSizeInBytesAdapter users use it in almost
identical ways, just with different PDFium APIs. It would be nice to
consolidate the repeated code. This adapter is also bit hard to use. To
address these issues, add a templated CallPDFiumWideStringBufferApi()
wrapper to avoid the repeated code, and hide the complexities of the
adapter. Then move PDFiumAPIStringBufferSizeInBytesAdapter to a nested
internal namespace, because it is now just an implementation detail.

Similarly, add CallPDFiumStringBufferApi() for use with
PDFiumAPIStringBufferAdapter<std::string>, and make
PDFiumAPIStringBufferAdapter part of the internal namespace.

For the rare use cases that cannot use either of the two helper
functions above, expose PDFiumAPIStringBufferAdapter outside of the
internal namespace.

Change-Id: I542e442c23d52f7322ec79a1a516fb8c48b28bb5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2208604
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770824}
This commit is contained in:
Lei Zhang
2020-05-20 23:09:45 +00:00
committed by Commit Bot
parent 6f06e81060
commit 4c820a945d
4 changed files with 89 additions and 82 deletions

@ -6,13 +6,13 @@
#include <stddef.h>
#include <string>
#include "base/check_op.h"
#include "base/strings/string_util.h"
namespace chrome_pdf {
namespace internal {
template <class StringType>
PDFiumAPIStringBufferAdapter<StringType>::PDFiumAPIStringBufferAdapter(
StringType* str,
@ -75,4 +75,6 @@ void PDFiumAPIStringBufferSizeInBytesAdapter::Close(size_t actual_size) {
template class PDFiumAPIStringBufferAdapter<std::string>;
template class PDFiumAPIStringBufferAdapter<base::string16>;
} // namespace internal
} // namespace chrome_pdf

@ -7,12 +7,17 @@
#include <stddef.h>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/numerics/safe_math.h"
#include "base/strings/string16.h"
namespace chrome_pdf {
namespace internal {
// Helper to deal with the fact that many PDFium APIs write the null-terminator
// into string buffers that are passed to them, but the PDF code likes to use
// std::strings / base::string16s, where one should not count on the internal
@ -94,6 +99,53 @@ class PDFiumAPIStringBufferSizeInBytesAdapter {
PDFiumAPIStringBufferAdapter<base::string16> adapter_;
};
template <class AdapterType,
class StringType,
typename BufferType,
typename ReturnType>
StringType CallPDFiumStringBufferApi(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
StringType str;
ReturnType expected_size = api.Run(nullptr, 0);
if (expected_size > 0) {
AdapterType api_string_adapter(&str, expected_size, check_expected_size);
auto* data = reinterpret_cast<BufferType*>(api_string_adapter.GetData());
api_string_adapter.Close(api.Run(data, expected_size));
}
return str;
}
} // namespace internal
// Helper function to call PDFium APIs where the output buffer is expected to
// hold UTF-16 data, and the buffer length is specified in bytes.
template <typename BufferType>
base::string16 CallPDFiumWideStringBufferApi(
base::RepeatingCallback<unsigned long(BufferType*, unsigned long)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
return internal::CallPDFiumStringBufferApi<adapter_type, base::string16>(
api, check_expected_size);
}
// Helper function to call PDFium APIs where the output buffer is expected to
// hold ASCII or UTF-8 data, and the buffer length is specified in bytes.
template <typename BufferType, typename ReturnType>
std::string CallPDFiumStringBufferApi(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferAdapter<std::string>;
return internal::CallPDFiumStringBufferApi<adapter_type, std::string>(
api, check_expected_size);
}
// Expose internal::PDFiumAPIStringBufferAdapter for special cases that cannot
// use the CallPDFiumStringBuffer* functions above.
template <class StringType>
using PDFiumAPIStringBufferAdapter =
internal::PDFiumAPIStringBufferAdapter<StringType>;
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_

@ -990,21 +990,15 @@ bool PDFiumEngine::ReadLoadedBytes(uint32_t length, void* buffer) {
void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle,
FPDF_PAGE page) {
unsigned long form_sel_text_len =
FORM_GetSelectedText(form_handle, page, nullptr, 0);
base::string16 selected_form_text16 = CallPDFiumWideStringBufferApi(
base::BindRepeating(&FORM_GetSelectedText, form_handle, page),
/*check_expected_size=*/false);
// If form selected text is empty and there was no previous form text
// selection, exit early because nothing has changed. When |form_sel_text_len|
// is 2, that represents a wide string with just a NUL-terminator.
if (form_sel_text_len <= 2 && selected_form_text_.empty())
// selection, exit early because nothing has changed.
if (selected_form_text16.empty() && selected_form_text_.empty())
return;
base::string16 selected_form_text16;
PDFiumAPIStringBufferSizeInBytesAdapter string_adapter(
&selected_form_text16, form_sel_text_len, false);
string_adapter.Close(FORM_GetSelectedText(
form_handle, page, string_adapter.GetData(), form_sel_text_len));
// Update previous and current selections, then compare them to check if
// selection has changed. If so, set plugin text selection.
std::string selected_form_text = selected_form_text_;
@ -2144,14 +2138,9 @@ pp::VarArray PDFiumEngine::GetBookmarks() {
pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
unsigned int depth) {
pp::VarDictionary dict;
base::string16 title;
unsigned long buffer_size = FPDFBookmark_GetTitle(bookmark, nullptr, 0);
if (buffer_size > 0) {
PDFiumAPIStringBufferSizeInBytesAdapter api_string_adapter(
&title, buffer_size, true);
api_string_adapter.Close(FPDFBookmark_GetTitle(
bookmark, api_string_adapter.GetData(), buffer_size));
}
base::string16 title = CallPDFiumWideStringBufferApi(
base::BindRepeating(&FPDFBookmark_GetTitle, bookmark),
/*check_expected_size=*/true);
dict.Set(pp::Var("title"), pp::Var(base::UTF16ToUTF8(title)));
FPDF_DEST dest = FPDFBookmark_GetDest(doc(), bookmark);
@ -2175,15 +2164,11 @@ pp::VarDictionary PDFiumEngine::TraverseBookmarks(FPDF_BOOKMARK bookmark,
} else {
// Extract URI for bookmarks linking to an external page.
FPDF_ACTION action = FPDFBookmark_GetAction(bookmark);
buffer_size = FPDFAction_GetURIPath(doc(), action, nullptr, 0);
if (buffer_size > 0) {
std::string uri;
PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
&uri, buffer_size, true);
api_string_adapter.Close(FPDFAction_GetURIPath(
doc(), action, api_string_adapter.GetData(), buffer_size));
std::string uri = CallPDFiumStringBufferApi(
base::BindRepeating(&FPDFAction_GetURIPath, doc(), action),
/*check_expected_size=*/true);
if (!uri.empty())
dict.Set(pp::Var("uri"), pp::Var(uri));
}
}
pp::VarArray children;
@ -3796,17 +3781,9 @@ void PDFiumEngine::LoadDocumentMetadata() {
std::string PDFiumEngine::GetMetadataByField(FPDF_BYTESTRING field) const {
DCHECK(doc());
size_t size =
FPDF_GetMetaText(doc(), field, /*buffer=*/nullptr, /*buflen=*/0);
if (size == 0)
return std::string();
base::string16 value;
PDFiumAPIStringBufferSizeInBytesAdapter string_adapter(
&value, size, /*check_expected_size=*/false);
string_adapter.Close(
FPDF_GetMetaText(doc(), field, string_adapter.GetData(), size));
return base::UTF16ToUTF8(value);
return base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
base::BindRepeating(&FPDF_GetMetaText, doc(), field),
/*check_expected_size=*/false));
}
PdfVersion PDFiumEngine::GetDocumentVersion() const {

@ -186,24 +186,6 @@ bool FloatEquals(float f1, float f2) {
kEpsilonScale * fmaxf(fmaxf(fabsf(f1), fabsf(f2)), kEpsilonScale);
}
using GetFormFieldPropertyFunction =
base::RepeatingCallback<unsigned long(unsigned short* buffer,
unsigned long buflen)>;
// Helper method to fetch string properties of form fields.
std::string GetFormFieldProperty(GetFormFieldPropertyFunction function) {
base::string16 data;
size_t buffer_size = function.Run(nullptr, 0);
if (buffer_size > 0) {
PDFiumAPIStringBufferSizeInBytesAdapter api_string_adapter(
&data, buffer_size, true);
api_string_adapter.Close(function.Run(
reinterpret_cast<unsigned short*>(api_string_adapter.GetData()),
buffer_size));
}
return base::UTF16ToUTF8(data);
}
// Count overlaps across text annotations.
template <typename T, typename U>
uint32_t CountOverlaps(const std::vector<T>& first_set,
@ -912,16 +894,11 @@ gfx::PointF PDFiumPage::TransformPageToScreenXY(const gfx::PointF& xy) {
PDFiumPage::Area PDFiumPage::GetURITarget(FPDF_ACTION uri_action,
LinkTarget* target) const {
if (target) {
size_t buffer_size =
FPDFAction_GetURIPath(engine_->doc(), uri_action, nullptr, 0);
if (buffer_size > 0) {
PDFiumAPIStringBufferAdapter<std::string> api_string_adapter(
&target->url, buffer_size, true);
void* data = api_string_adapter.GetData();
size_t bytes_written =
FPDFAction_GetURIPath(engine_->doc(), uri_action, data, buffer_size);
api_string_adapter.Close(bytes_written);
}
std::string url = CallPDFiumStringBufferApi(
base::BindRepeating(&FPDFAction_GetURIPath, engine_->doc(), uri_action),
/*check_expected_size=*/true);
if (!url.empty())
target->url = url;
}
return WEBLINK_AREA;
}
@ -968,6 +945,8 @@ void PDFiumPage::PopulateWebLinks() {
ScopedFPDFPageLink links(FPDFLink_LoadWebLinks(GetTextPage()));
int count = FPDFLink_CountWebLinks(links.get());
for (int i = 0; i < count; ++i) {
// WARNING: FPDFLink_GetURL() is not compatible with
// CallPDFiumWideStringBufferApi().
base::string16 url;
int url_length = FPDFLink_GetURL(links.get(), i, nullptr, 0);
if (url_length > 0) {
@ -1153,16 +1132,11 @@ void PDFiumPage::PopulateImageAltTextForStructElement(
auto it = marked_content_id_image_map.find(marked_content_id);
if (it != marked_content_id_image_map.end() &&
images_[it->second].alt_text.empty()) {
size_t buffer_size =
FPDF_StructElement_GetAltText(current_element, nullptr, 0);
if (buffer_size > 0) {
base::string16 alt_text;
PDFiumAPIStringBufferSizeInBytesAdapter api_string_adapter(
&alt_text, buffer_size, true);
api_string_adapter.Close(FPDF_StructElement_GetAltText(
current_element, api_string_adapter.GetData(), buffer_size));
images_[it->second].alt_text = base::UTF16ToUTF8(alt_text);
}
images_[it->second].alt_text =
base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
base::BindRepeating(&FPDF_StructElement_GetAltText,
current_element),
/*check_expected_size=*/true));
}
}
int children_count = FPDF_StructElement_CountChildren(current_element);
@ -1260,10 +1234,12 @@ void PDFiumPage::PopulateTextField(FPDF_ANNOTATION annot) {
text_field.bounding_rect =
PageToScreen(pp::Point(), 1.0, rect.left, rect.top, rect.right,
rect.bottom, PageOrientation::kOriginal);
text_field.value = GetFormFieldProperty(
base::BindRepeating(FPDFAnnot_GetFormFieldValue, form_handle, annot));
text_field.name = GetFormFieldProperty(
base::BindRepeating(FPDFAnnot_GetFormFieldName, form_handle, annot));
text_field.value = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
base::BindRepeating(&FPDFAnnot_GetFormFieldValue, form_handle, annot),
/*check_expected_size=*/true));
text_field.name = base::UTF16ToUTF8(CallPDFiumWideStringBufferApi(
base::BindRepeating(&FPDFAnnot_GetFormFieldName, form_handle, annot),
/*check_expected_size=*/true));
text_field.flags = FPDFAnnot_GetFormFieldFlags(form_handle, annot);
text_fields_.push_back(std::move(text_field));
}