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:
@ -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));
|
||||
}
|
||||
|
Reference in New Issue
Block a user