0

Add the pdf plugin's source in src\pdf.

I've updated gypi files to not use internal_pdf variable anymore, which was brought in from pdf repo's supplemental.gypi.

R=thestig@chromium.org
TBR=darin

Review URL: https://codereview.chromium.org/294793003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271531 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
jam@chromium.org
2014-05-20 01:56:40 +00:00
parent f0d119a1eb
commit 1b1e9effe9
63 changed files with 15773 additions and 47 deletions

@ -1103,6 +1103,7 @@
'../ipc/ipc.gyp:ipc_tests',
'../media/media.gyp:media_unittests',
'../net/net.gyp:net_unittests_run',
'../pdf/pdf.gyp:pdf',
'../printing/printing.gyp:printing_unittests',
'../remoting/remoting.gyp:remoting_webapp',
'../sql/sql.gyp:sql_unittests',
@ -1114,11 +1115,6 @@
'../url/url.gyp:url_unittests',
],
'conditions': [
['internal_pdf', {
'dependencies': [
'../pdf/pdf.gyp:pdf',
],
}], # internal_pdf
['target_arch=="ia32"', {
'dependencies': [
'../chrome/chrome.gyp:crash_service_win64',

@ -1275,9 +1275,6 @@
# Build libpeerconnection as a static library by default.
'libpeer_target_type%': 'static_library',
# Set to 1 to compile with the built in pdf viewer.
'internal_pdf%': 0,
# Set to 1 to compile with the OpenGL ES 2.0 conformance tests.
'internal_gles2_conform_tests%': 0,

@ -282,6 +282,9 @@
'app/chrome_main_mac.mm',
'app/chrome_main_mac.h',
],
'dependencies': [
'../pdf/pdf.gyp:pdf',
],
'include_dirs': [
'<(grit_out_dir)',
],
@ -319,11 +322,6 @@
'../components/components.gyp:breakpad_stubs',
],
}], # mac_breakpad_compiled_in
['internal_pdf', {
'dependencies': [
'../pdf/pdf.gyp:pdf',
],
}],
], # conditions
}], # OS=="mac"
], # conditions

@ -76,6 +76,7 @@
# Bring in pdfsqueeze and run it on all pdfs
'../build/temp_gyp/pdfsqueeze.gyp:pdfsqueeze',
'../crypto/crypto.gyp:crypto',
'../pdf/pdf.gyp:pdf',
# On Mac, Flash gets put into the framework, so we need this
# dependency here. flash_player.gyp will copy the Flash bundle
# into PRODUCT_DIR.
@ -146,13 +147,10 @@
},
{
'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Internet Plug-Ins',
'files': [],
'files': [
'<(PRODUCT_DIR)/PDF.plugin',
],
'conditions': [
['internal_pdf', {
'files': [
'<(PRODUCT_DIR)/PDF.plugin',
],
}],
['disable_nacl!=1', {
'files': [
'<(PRODUCT_DIR)/ppGoogleNaClPluginChrome.plugin',
@ -278,11 +276,6 @@
},
],
}], # mac_keystone
['internal_pdf', {
'dependencies': [
'../pdf/pdf.gyp:pdf',
],
}],
['debug_devtools==1', {
'postbuilds': [{
'postbuild_name': 'Copy inspector files',

@ -368,7 +368,7 @@
'--breakpad=0',
'--keystone=<(mac_keystone)',
'--scm=1',
'--pdf=<(internal_pdf)',
'--pdf=1',
'--bundle_id=<(mac_bundle_id)'],
},
{
@ -430,23 +430,17 @@
# chrome/app/theme/google_chrome/BRANDING have the short name
# "chrome" etc.; should we try to extract from there instead?
# On Mac, this is done in chrome_dll.gypi.
['internal_pdf', {
# CrOS does this in a separate build step.
['OS=="linux" and chromeos==0 and linux_dump_symbols==1', {
'dependencies': [
'../pdf/pdf.gyp:pdf',
'../pdf/pdf.gyp:pdf_linux_symbols',
],
'conditions': [
# CrOS does this in a separate build step.
['OS=="linux" and chromeos==0 and linux_dump_symbols==1', {
'dependencies': [
'../pdf/pdf.gyp:pdf_linux_symbols',
],
}], # OS=="linux" and chromeos==0 and linux_dump_symbols==1
],
}], # internal_pdf
}], # OS=="linux" and chromeos==0 and linux_dump_symbols==1
],
'dependencies': [
'../components/components.gyp:startup_metric_utils',
# On Mac, this is done in chrome_dll.gypi.
'../pdf/pdf.gyp:pdf',
'chrome_resources.gyp:packed_extra_resources',
'chrome_resources.gyp:packed_resources',
# Copy Flash Player files to PRODUCT_DIR if applicable. Let the .gyp

@ -495,6 +495,7 @@
'<(PRODUCT_DIR)/chrome',
'<(PRODUCT_DIR)/chrome_sandbox',
'<(PRODUCT_DIR)/libffmpegsumo.so',
'<(PRODUCT_DIR)/libpdf.so',
'<(PRODUCT_DIR)/libppGoogleNaClPluginChrome.so',
'<(PRODUCT_DIR)/xdg-mime',
'<(PRODUCT_DIR)/xdg-settings',
@ -541,11 +542,6 @@
'deb_arch': 'arm',
'rpm_arch': 'arm',
}],
['internal_pdf', {
'packaging_files_binaries': [
'<(PRODUCT_DIR)/libpdf.so',
],
}],
['libpeer_target_type!="static_library"', {
'packaging_files_binaries': [
'<(PRODUCT_DIR)/lib/libpeerconnection.so',

@ -1770,11 +1770,6 @@
['exclude', '^browser/captive_portal/'],
],
}],
['internal_pdf', {
'dependencies': [
'../pdf/pdf.gyp:pdf',
],
}],
['enable_webrtc==0', {
'sources!': [
'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc',

5
pdf/DEPS Normal file

@ -0,0 +1,5 @@
include_rules = [
"+net",
"+ppapi",
"+third_party/pdfium/fpdfsdk/include",
]

44
pdf/Info.plist Normal file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.chromium.pdf_plugin</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>BRPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFPlugInDynamicRegisterFunction</key>
<string></string>
<key>CFPlugInDynamicRegistration</key>
<string>NO</string>
<key>WebPluginDescription</key>
<string>Chrome PDF Viewer</string>
<key>WebPluginMIMETypes</key>
<dict>
<key>application/pdf</key>
<dict>
<key>WebPluginExtensions</key>
<array>
<string>pdf</string>
</array>
<key>WebPluginTypeDescription</key>
<string>Acrobat Portable Document Format</string>
</dict>
</dict>
<key>WebPluginName</key>
<string>Chrome PDF Viewer</string>
</dict>
</plist>

5
pdf/OWNERS Normal file

@ -0,0 +1,5 @@
cevans@chromium.org
gene@chromium.org
jam@chromium.org
raymes@chromium.org
thestig@chromium.org

179
pdf/button.cc Normal file

@ -0,0 +1,179 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/button.h"
#include "base/logging.h"
#include "pdf/draw_utils.h"
#include "ppapi/cpp/input_event.h"
namespace chrome_pdf {
Button::Button()
: style_(BUTTON_CLICKABLE), state_(BUTTON_NORMAL), is_pressed_(false) {
}
Button::~Button() {
}
bool Button::CreateButton(uint32 id,
const pp::Point& origin,
bool visible,
Control::Owner* owner,
ButtonStyle style,
const pp::ImageData& face_normal,
const pp::ImageData& face_highlighted,
const pp::ImageData& face_pressed) {
DCHECK(face_normal.size().GetArea());
DCHECK(face_normal.size() == face_highlighted.size());
DCHECK(face_normal.size() == face_pressed.size());
pp::Rect rc(origin, face_normal.size());
if (!Control::Create(id, rc, visible, owner))
return false;
style_ = style;
normal_ = face_normal;
highlighted_ = face_highlighted;
pressed_ = face_pressed;
return true;
}
void Button::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
if (!visible())
return;
pp::Rect draw_rc = rc.Intersect(rect());
if (draw_rc.IsEmpty())
return;
pp::Point origin = draw_rc.point();
draw_rc.Offset(-rect().x(), -rect().y());
AlphaBlend(GetCurrentImage(), draw_rc, image_data, origin, transparency());
}
bool Button::HandleEvent(const pp::InputEvent& event) {
if (!visible())
return false;
// Button handles mouse events only.
pp::MouseInputEvent mouse_event(event);
if (mouse_event.is_null())
return false;
pp::Point pt = mouse_event.GetPosition();
if (!rect().Contains(pt) ||
event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
ChangeState(BUTTON_NORMAL, false);
owner()->SetEventCapture(id(), false);
return false;
}
owner()->SetCursor(id(), PP_CURSORTYPE_POINTER);
owner()->SetEventCapture(id(), true);
bool handled = true;
switch (event.GetType()) {
case PP_INPUTEVENT_TYPE_MOUSEMOVE:
if (state_ == BUTTON_NORMAL)
ChangeState(BUTTON_HIGHLIGHTED, false);
break;
case PP_INPUTEVENT_TYPE_MOUSEDOWN:
if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
ChangeState(BUTTON_PRESSED, false);
is_pressed_ = true;
}
break;
case PP_INPUTEVENT_TYPE_MOUSEUP:
if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
is_pressed_) {
OnButtonClicked();
is_pressed_ = false;
} else {
// Since button has not been pressed, return false to allow other
// controls (scrollbar) to process mouse button up.
return false;
}
break;
default:
handled = false;
break;
}
return handled;
}
void Button::OnEventCaptureReleased() {
ChangeState(BUTTON_NORMAL, false);
}
void Button::Show(bool visible, bool invalidate) {
// If button become invisible, remove pressed flag.
if (!visible)
is_pressed_ = false;
Control::Show(visible, invalidate);
}
void Button::AdjustTransparency(uint8 transparency, bool invalidate) {
// If button become invisible, remove pressed flag.
if (transparency == kTransparentAlpha)
is_pressed_ = false;
Control::AdjustTransparency(transparency, invalidate);
}
void Button::SetPressedState(bool pressed) {
if (style_ == BUTTON_STATE) {
if (IsPressed() != pressed)
ChangeState(pressed ? BUTTON_PRESSED_STICKY : BUTTON_NORMAL, true);
}
}
const pp::ImageData& Button::GetCurrentImage() {
switch (state_) {
case BUTTON_NORMAL: return normal_;
case BUTTON_HIGHLIGHTED: return highlighted_;
case BUTTON_PRESSED:
case BUTTON_PRESSED_STICKY: return pressed_;
}
NOTREACHED();
return normal_;
}
void Button::ChangeState(ButtonState new_state, bool force) {
if (style_ == BUTTON_STATE && !force) {
// If button is a state button and pressed state is sticky,
// user have to click on this button again to unpress it.
if ((state_ == BUTTON_PRESSED_STICKY && new_state != BUTTON_PRESSED_STICKY)
||
(state_ != BUTTON_PRESSED_STICKY && new_state == BUTTON_PRESSED_STICKY))
return;
}
if (state_ != new_state) {
state_ = new_state;
owner()->Invalidate(id(), rect());
}
}
void Button::OnButtonClicked() {
switch (style_) {
case BUTTON_CLICKABLE:
ChangeState(BUTTON_HIGHLIGHTED, true);
owner()->OnEvent(id(), EVENT_ID_BUTTON_CLICKED, NULL);
break;
case BUTTON_STATE:
SetPressedState(!IsPressed());
owner()->OnEvent(id(), EVENT_ID_BUTTON_STATE_CHANGED, NULL);
break;
default:
NOTREACHED();
}
}
} // namespace chrome_pdf

71
pdf/button.h Normal file

@ -0,0 +1,71 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_BUTTON_H_
#define PDF_BUTTON_H_
#include "pdf/control.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/rect.h"
namespace chrome_pdf {
class Button : public Control {
public:
enum ButtonEventIds {
EVENT_ID_BUTTON_CLICKED,
EVENT_ID_BUTTON_STATE_CHANGED,
};
enum ButtonStyle {
BUTTON_CLICKABLE,
BUTTON_STATE
};
enum ButtonState {
BUTTON_NORMAL,
BUTTON_HIGHLIGHTED,
BUTTON_PRESSED,
BUTTON_PRESSED_STICKY,
};
Button();
virtual ~Button();
virtual bool CreateButton(uint32 id,
const pp::Point& origin,
bool visible,
Control::Owner* delegate,
ButtonStyle style,
const pp::ImageData& face_normal,
const pp::ImageData& face_highlighted,
const pp::ImageData& face_pressed);
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc);
virtual bool HandleEvent(const pp::InputEvent& event);
virtual void OnEventCaptureReleased();
virtual void Show(bool visible, bool invalidate);
virtual void AdjustTransparency(uint8 transparency, bool invalidate);
ButtonState state() const { return state_; }
bool IsPressed() const { return state() == BUTTON_PRESSED_STICKY; }
void SetPressedState(bool pressed);
private:
void OnButtonClicked();
const pp::ImageData& GetCurrentImage();
void ChangeState(ButtonState new_state, bool force);
ButtonStyle style_;
ButtonState state_;
bool is_pressed_;
pp::ImageData normal_;
pp::ImageData highlighted_;
pp::ImageData pressed_;
};
} // namespace chrome_pdf
#endif // PDF_BUTTON_H_

172
pdf/chunk_stream.cc Normal file

@ -0,0 +1,172 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/chunk_stream.h"
#define __STDC_LIMIT_MACROS
#ifdef _WIN32
#include <limits.h>
#else
#include <stdint.h>
#endif
#include <algorithm>
#include "base/basictypes.h"
namespace chrome_pdf {
ChunkStream::ChunkStream() {
}
ChunkStream::~ChunkStream() {
}
void ChunkStream::Clear() {
chunks_.clear();
data_.clear();
}
void ChunkStream::Preallocate(size_t stream_size) {
data_.reserve(stream_size);
}
size_t ChunkStream::GetSize() {
return data_.size();
}
bool ChunkStream::WriteData(size_t offset, void* buffer, size_t size) {
if (SIZE_MAX - size < offset)
return false;
if (data_.size() < offset + size)
data_.resize(offset + size);
memcpy(&data_[offset], buffer, size);
if (chunks_.empty()) {
chunks_[offset] = size;
return true;
}
std::map<size_t, size_t>::iterator start = chunks_.upper_bound(offset);
if (start != chunks_.begin())
--start; // start now points to the key equal or lower than offset.
if (start->first + start->second < offset)
++start; // start element is entirely before current chunk, skip it.
std::map<size_t, size_t>::iterator end = chunks_.upper_bound(offset + size);
if (start == end) { // No chunks to merge.
chunks_[offset] = size;
return true;
}
--end;
size_t new_offset = std::min<size_t>(start->first, offset);
size_t new_size =
std::max<size_t>(end->first + end->second, offset + size) - new_offset;
chunks_.erase(start, ++end);
chunks_[new_offset] = new_size;
return true;
}
bool ChunkStream::ReadData(size_t offset, size_t size, void* buffer) const {
if (!IsRangeAvailable(offset, size))
return false;
memcpy(buffer, &data_[offset], size);
return true;
}
bool ChunkStream::GetMissedRanges(
size_t offset, size_t size,
std::vector<std::pair<size_t, size_t> >* ranges) const {
if (IsRangeAvailable(offset, size))
return false;
ranges->clear();
if (chunks_.empty()) {
ranges->push_back(std::pair<size_t, size_t>(offset, size));
return true;
}
std::map<size_t, size_t>::const_iterator start = chunks_.upper_bound(offset);
if (start != chunks_.begin())
--start; // start now points to the key equal or lower than offset.
if (start->first + start->second < offset)
++start; // start element is entirely before current chunk, skip it.
std::map<size_t, size_t>::const_iterator end =
chunks_.upper_bound(offset + size);
if (start == end) { // No data in the current range available.
ranges->push_back(std::pair<size_t, size_t>(offset, size));
return true;
}
size_t cur_offset = offset;
std::map<size_t, size_t>::const_iterator it;
for (it = start; it != end; ++it) {
if (cur_offset < it->first) {
size_t new_size = it->first - cur_offset;
ranges->push_back(std::pair<size_t, size_t>(cur_offset, new_size));
cur_offset = it->first + it->second;
} else if (cur_offset < it->first + it->second) {
cur_offset = it->first + it->second;
}
}
// Add last chunk.
if (cur_offset < offset + size)
ranges->push_back(std::pair<size_t, size_t>(cur_offset,
offset + size - cur_offset));
return true;
}
bool ChunkStream::IsRangeAvailable(size_t offset, size_t size) const {
if (chunks_.empty())
return false;
if (SIZE_MAX - size < offset)
return false;
std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
if (it == chunks_.begin())
return false; // No chunks includes offset byte.
--it; // Now it starts equal or before offset.
return (it->first + it->second) >= (offset + size);
}
size_t ChunkStream::GetFirstMissingByte() const {
if (chunks_.empty())
return 0;
std::map<size_t, size_t>::const_iterator begin = chunks_.begin();
return begin->first > 0 ? 0 : begin->second;
}
size_t ChunkStream::GetLastByteBefore(size_t offset) const {
if (chunks_.empty())
return 0;
std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
if (it == chunks_.begin())
return 0;
--it;
return it->first + it->second;
}
size_t ChunkStream::GetFirstByteAfter(size_t offset) const {
if (chunks_.empty())
return 0;
std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
if (it == chunks_.end())
return data_.size();
return it->first;
}
} // namespace chrome_pdf

48
pdf/chunk_stream.h Normal file

@ -0,0 +1,48 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_CHUNK_STREAM_H_
#define PDF_CHUNK_STREAM_H_
#include <stddef.h>
#include <map>
#include <vector>
namespace chrome_pdf {
// This class collects a chunks of data into one data stream. Client can check
// if data in certain range is available, and get missing chunks of data.
class ChunkStream {
public:
ChunkStream();
~ChunkStream();
void Clear();
void Preallocate(size_t stream_size);
size_t GetSize();
bool WriteData(size_t offset, void* buffer, size_t size);
bool ReadData(size_t offset, size_t size, void* buffer) const;
// Returns vector of pairs where first is an offset, second is a size.
bool GetMissedRanges(size_t offset, size_t size,
std::vector<std::pair<size_t, size_t> >* ranges) const;
bool IsRangeAvailable(size_t offset, size_t size) const;
size_t GetFirstMissingByte() const;
size_t GetLastByteBefore(size_t offset) const;
size_t GetFirstByteAfter(size_t offset) const;
private:
std::vector<unsigned char> data_;
// Pair, first - begining of the chunk, second - size of the chunk.
std::map<size_t, size_t> chunks_;
};
}; // namespace chrome_pdf
#endif

114
pdf/control.cc Normal file

@ -0,0 +1,114 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/control.h"
#include "base/logging.h"
#include "pdf/draw_utils.h"
namespace chrome_pdf {
Control::Control()
: id_(kInvalidControlId),
visible_(false),
owner_(NULL),
transparency_(kOpaqueAlpha) {
}
Control::~Control() {
}
bool Control::Create(uint32 id, const pp::Rect& rc,
bool visible, Owner* owner) {
DCHECK(owner);
if (owner_ || id == kInvalidControlId)
return false; // Already created or id is invalid.
id_ = id;
rc_ = rc;
visible_ = visible;
owner_ = owner;
return true;
}
bool Control::HandleEvent(const pp::InputEvent& event) {
return false;
}
void Control::PaintMultipleRects(pp::ImageData* image_data,
const std::list<pp::Rect>& rects) {
DCHECK(rects.size() > 0);
if (rects.size() == 1) {
Paint(image_data, rects.front());
return;
}
// Some rects in the input list may overlap. To prevent double
// paining (causes problems with semi-transparent controls) we'll
// paint control into buffer image data only once and copy requested
// rectangles.
pp::ImageData buffer(owner()->GetInstance(), image_data->format(),
rect().size(), false);
pp::Rect draw_rc = pp::Rect(image_data->size()).Intersect(rect());
pp::Rect ctrl_rc = pp::Rect(rect().point() - draw_rc.point(), draw_rc.size());
CopyImage(*image_data, draw_rc, &buffer, ctrl_rc, false);
// Temporary move control to origin (0,0) and draw it into temp buffer.
// Move to the original position afterward. Since this is going on temp
// buffer, we don't need to invalidate here.
pp::Rect temp = rect();
MoveTo(pp::Point(0, 0), false);
Paint(&buffer, ctrl_rc);
MoveTo(temp.point(), false);
std::list<pp::Rect>::const_iterator iter;
for (iter = rects.begin(); iter != rects.end(); ++iter) {
pp::Rect draw_rc = rect().Intersect(*iter);
if (!draw_rc.IsEmpty()) {
// Copy requested rect from the buffer image.
pp::Rect src_rc = draw_rc;
src_rc.Offset(-rect().x(), -rect().y());
CopyImage(buffer, src_rc, image_data, draw_rc, false);
}
}
}
void Control::Show(bool visible, bool invalidate) {
if (visible_ != visible) {
visible_ = visible;
if (invalidate)
owner_->Invalidate(id_, rc_);
}
}
void Control::AdjustTransparency(uint8 transparency, bool invalidate) {
if (transparency_ != transparency) {
transparency_ = transparency;
if (invalidate && visible_)
owner_->Invalidate(id_, rc_);
}
}
void Control::MoveBy(const pp::Point& offset, bool invalidate) {
pp::Rect old_rc = rc_;
rc_.Offset(offset);
if (invalidate && visible_) {
owner()->Invalidate(id(), old_rc);
owner()->Invalidate(id(), rect());
}
}
void Control::SetRect(const pp::Rect& rc, bool invalidate) {
pp::Rect old_rc = rc_;
rc_ = rc;
if (invalidate && visible_) {
owner()->Invalidate(id(), old_rc);
owner()->Invalidate(id(), rect());
}
}
void Control::MoveTo(const pp::Point& origin, bool invalidate) {
MoveBy(origin - rc_.point(), invalidate);
}
} // namespace chrome_pdf

77
pdf/control.h Normal file

@ -0,0 +1,77 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_CONTROL_H_
#define PDF_CONTROL_H_
#include <list>
#include "base/basictypes.h"
#include "ppapi/c/dev/pp_cursor_type_dev.h"
#include "ppapi/cpp/rect.h"
namespace pp {
class ImageData;
class InputEvent;
class Instance;
}
namespace chrome_pdf {
const uint32 kInvalidControlId = 0;
class Control {
public:
class Owner {
public:
virtual ~Owner() {}
virtual void OnEvent(uint32 control_id, uint32 event_id, void* data) = 0;
virtual void Invalidate(uint32 control_id, const pp::Rect& rc) = 0;
virtual uint32 ScheduleTimer(uint32 control_id, uint32 timeout_ms) = 0;
virtual void SetEventCapture(uint32 control_id, bool set_capture) = 0;
virtual void SetCursor(uint32 control_id,
PP_CursorType_Dev cursor_type) = 0;
virtual pp::Instance* GetInstance() = 0;
};
Control();
virtual ~Control();
virtual bool Create(uint32 id, const pp::Rect& rc,
bool visible, Owner* owner);
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc) {}
virtual bool HandleEvent(const pp::InputEvent& event);
virtual void OnTimerFired(uint32 timer_id) {}
virtual void EventCaptureReleased() {}
// Paint control into multiple destination rects.
virtual void PaintMultipleRects(pp::ImageData* image_data,
const std::list<pp::Rect>& rects);
virtual void Show(bool visible, bool invalidate);
virtual void AdjustTransparency(uint8 transparency, bool invalidate);
virtual void MoveBy(const pp::Point& offset, bool invalidate);
virtual void SetRect(const pp::Rect& rc, bool invalidate);
void MoveTo(const pp::Point& origin, bool invalidate);
uint32 id() const { return id_; }
const pp::Rect& rect() const { return rc_; }
bool visible() const { return visible_; }
Owner* owner() { return owner_; }
uint8 transparency() const { return transparency_; }
private:
uint32 id_;
pp::Rect rc_;
bool visible_;
Owner* owner_;
uint8 transparency_;
};
typedef Control::Owner ControlOwner;
} // namespace chrome_pdf
#endif // PDF_CONTROL_H_

515
pdf/document_loader.cc Normal file

@ -0,0 +1,515 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/document_loader.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "net/http/http_util.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/url_request_info.h"
#include "ppapi/cpp/url_response_info.h"
namespace chrome_pdf {
// Document below size will be downloaded in one chunk.
const uint32 kMinFileSize = 64*1024;
DocumentLoader::DocumentLoader(Client* client)
: client_(client), partial_document_(false), request_pending_(false),
current_pos_(0), current_chunk_size_(0), current_chunk_read_(0),
document_size_(0), header_request_(true), is_multipart_(false) {
loader_factory_.Initialize(this);
}
DocumentLoader::~DocumentLoader() {
}
bool DocumentLoader::Init(const pp::URLLoader& loader,
const std::string& url,
const std::string& headers) {
DCHECK(url_.empty());
url_ = url;
loader_ = loader;
std::string response_headers;
if (!headers.empty()) {
response_headers = headers;
} else {
pp::URLResponseInfo response = loader_.GetResponseInfo();
pp::Var headers_var = response.GetHeaders();
if (headers_var.is_string()) {
response_headers = headers_var.AsString();
}
}
bool accept_ranges_bytes = false;
bool content_encoded = false;
uint32 content_length = 0;
std::string type;
std::string disposition;
if (!response_headers.empty()) {
net::HttpUtil::HeadersIterator it(response_headers.begin(),
response_headers.end(), "\n");
while (it.GetNext()) {
if (LowerCaseEqualsASCII(it.name(), "content-length")) {
content_length = atoi(it.values().c_str());
} else if (LowerCaseEqualsASCII(it.name(), "accept-ranges")) {
accept_ranges_bytes = LowerCaseEqualsASCII(it.values(), "bytes");
} else if (LowerCaseEqualsASCII(it.name(), "content-encoding")) {
content_encoded = true;
} else if (LowerCaseEqualsASCII(it.name(), "content-type")) {
type = it.values();
size_t semi_colon_pos = type.find(';');
if (semi_colon_pos != std::string::npos) {
type = type.substr(0, semi_colon_pos);
}
TrimWhitespace(type, base::TRIM_ALL, &type);
} else if (LowerCaseEqualsASCII(it.name(), "content-disposition")) {
disposition = it.values();
}
}
}
if (!type.empty() &&
!EndsWith(type, "/pdf", false) &&
!EndsWith(type, ".pdf", false) &&
!EndsWith(type, "/x-pdf", false) &&
!EndsWith(type, "/*", false) &&
!EndsWith(type, "/acrobat", false) &&
!EndsWith(type, "/unknown", false) &&
!StartsWithASCII(url, "blob:", false)) {
return false;
}
if (StartsWithASCII(disposition, "attachment", false)) {
return false;
}
if (content_length > 0)
chunk_stream_.Preallocate(content_length);
document_size_ = content_length;
requests_count_ = 0;
// Document loading strategy.
// Following table shows the growth on the minimal request size depending
// on the number requests that has been made already.
chunk_size_table_[10] = 32*1024;
chunk_size_table_[20] = 64*1024;
chunk_size_table_[30] = 128*1024;
chunk_size_table_[40] = 256*1024;
chunk_size_table_[50] = 512*1024;
chunk_size_table_[60] = 1024*1024;
chunk_size_table_[70] = 2048*1024;
// Enable partial loading only if file size is above the threshold.
// It will allow avoiding latency for multiple requests.
if (content_length > kMinFileSize &&
accept_ranges_bytes &&
!content_encoded) {
LoadPartialDocument();
} else {
LoadFullDocument();
}
return true;
}
void DocumentLoader::LoadPartialDocument() {
partial_document_ = true;
// Force the main request to be cancelled, since if we're a full-frame plugin
// there could be other references to the loader.
loader_.Close();
loader_ = pp::URLLoader();
// Download file header.
header_request_ = true;
RequestData(0, std::min(GetRequestSize(), document_size_));
}
void DocumentLoader::LoadFullDocument() {
partial_document_ = false;
chunk_buffer_.clear();
ReadMore();
}
bool DocumentLoader::IsDocumentComplete() const {
if (document_size_ == 0) // Document size unknown.
return false;
return IsDataAvailable(0, document_size_);
}
uint32 DocumentLoader::GetAvailableData() const {
if (document_size_ == 0) { // If document size is unknown.
return current_pos_;
}
std::vector<std::pair<size_t, size_t> > ranges;
chunk_stream_.GetMissedRanges(0, document_size_, &ranges);
uint32 available = document_size_;
std::vector<std::pair<size_t, size_t> >::iterator it;
for (it = ranges.begin(); it != ranges.end(); ++it) {
available -= it->second;
}
return available;
}
void DocumentLoader::ClearPendingRequests() {
// The first item in the queue is pending (need to keep it in the queue).
if (pending_requests_.size() > 1) {
// Remove all elements except the first one.
pending_requests_.erase(++pending_requests_.begin(),
pending_requests_.end());
}
}
bool DocumentLoader::GetBlock(uint32 position, uint32 size, void* buf) const {
return chunk_stream_.ReadData(position, size, buf);
}
bool DocumentLoader::IsDataAvailable(uint32 position, uint32 size) const {
return chunk_stream_.IsRangeAvailable(position, size);
}
void DocumentLoader::RequestData(uint32 position, uint32 size) {
DCHECK(partial_document_);
// We have some artefact request from
// PDFiumEngine::OnDocumentComplete() -> FPDFAvail_IsPageAvail after
// document is complete.
// We need this fix in PDFIum. Adding this as a work around.
// Bug: http://code.google.com/p/chromium/issues/detail?id=79996
// Test url:
// http://www.icann.org/en/correspondence/holtzman-to-jeffrey-02mar11-en.pdf
if (IsDocumentComplete())
return;
pending_requests_.push_back(std::pair<size_t, size_t>(position, size));
DownloadPendingRequests();
}
void DocumentLoader::DownloadPendingRequests() {
if (request_pending_ || pending_requests_.empty())
return;
// Remove already completed requests.
// By design DownloadPendingRequests() should have at least 1 request in the
// queue. ReadComplete() will remove the last pending comment from the queue.
while (pending_requests_.size() > 1) {
if (IsDataAvailable(pending_requests_.front().first,
pending_requests_.front().second)) {
pending_requests_.pop_front();
} else {
break;
}
}
uint32 pos = pending_requests_.front().first;
uint32 size = pending_requests_.front().second;
if (IsDataAvailable(pos, size)) {
ReadComplete();
return;
}
// If current request has been partially downloaded already, split it into
// a few smaller requests.
std::vector<std::pair<size_t, size_t> > ranges;
chunk_stream_.GetMissedRanges(pos, size, &ranges);
if (ranges.size() > 0) {
pending_requests_.pop_front();
pending_requests_.insert(pending_requests_.begin(),
ranges.begin(), ranges.end());
pos = pending_requests_.front().first;
size = pending_requests_.front().second;
}
uint32 cur_request_size = GetRequestSize();
// If size is less than default request, try to expand download range for
// more optimal download.
if (size < cur_request_size && partial_document_) {
// First, try to expand block towards the end of the file.
uint32 new_pos = pos;
uint32 new_size = cur_request_size;
if (pos + new_size > document_size_)
new_size = document_size_ - pos;
std::vector<std::pair<size_t, size_t> > ranges;
if (chunk_stream_.GetMissedRanges(new_pos, new_size, &ranges)) {
new_pos = ranges[0].first;
new_size = ranges[0].second;
}
// Second, try to expand block towards the beginning of the file.
if (new_size < cur_request_size) {
uint32 block_end = new_pos + new_size;
if (block_end > cur_request_size) {
new_pos = block_end - cur_request_size;
} else {
new_pos = 0;
}
new_size = block_end - new_pos;
if (chunk_stream_.GetMissedRanges(new_pos, new_size, &ranges)) {
new_pos = ranges.back().first;
new_size = ranges.back().second;
}
}
pos = new_pos;
size = new_size;
}
size_t last_byte_before = chunk_stream_.GetLastByteBefore(pos);
size_t first_byte_after = chunk_stream_.GetFirstByteAfter(pos + size - 1);
if (pos - last_byte_before < cur_request_size) {
size = pos + size - last_byte_before;
pos = last_byte_before;
}
if ((pos + size < first_byte_after) &&
(pos + size + cur_request_size >= first_byte_after))
size = first_byte_after - pos;
request_pending_ = true;
// Start downloading first pending request.
loader_.Close();
loader_ = client_->CreateURLLoader();
pp::CompletionCallback callback =
loader_factory_.NewCallback(&DocumentLoader::DidOpen);
pp::URLRequestInfo request = GetRequest(pos, size);
requests_count_++;
int rv = loader_.Open(request, callback);
if (rv != PP_OK_COMPLETIONPENDING)
callback.Run(rv);
}
pp::URLRequestInfo DocumentLoader::GetRequest(uint32 position,
uint32 size) const {
pp::URLRequestInfo request(client_->GetPluginInstance());
request.SetURL(url_.c_str());
request.SetMethod("GET");
request.SetFollowRedirects(true);
const size_t kBufSize = 100;
char buf[kBufSize];
// According to rfc2616, byte range specifies position of the first and last
// bytes in the requested range inclusively. Therefore we should subtract 1
// from the position + size, to get index of the last byte that needs to be
// downloaded.
base::snprintf(buf, kBufSize, "Range: bytes=%d-%d", position,
position + size - 1);
pp::Var header(buf);
request.SetHeaders(header);
return request;
}
void DocumentLoader::DidOpen(int32_t result) {
if (result != PP_OK) {
NOTREACHED();
return;
}
is_multipart_ = false;
current_chunk_size_ = 0;
current_chunk_read_ = 0;
pp::Var headers_var = loader_.GetResponseInfo().GetHeaders();
std::string headers;
if (headers_var.is_string())
headers = headers_var.AsString();
std::string boundary = GetMultiPartBoundary(headers);
if (boundary.size()) {
// Leave position untouched for now, when we read the data we'll get it.
is_multipart_ = true;
multipart_boundary_ = boundary;
} else {
// Need to make sure that the server returned a byte-range, since it's
// possible for a server to just ignore our bye-range request and just
// return the entire document even if it supports byte-range requests.
// i.e. sniff response to
// http://www.act.org/compass/sample/pdf/geometry.pdf
current_pos_ = 0;
uint32 start_pos, end_pos;
if (GetByteRange(headers, &start_pos, &end_pos)) {
current_pos_ = start_pos;
if (end_pos && end_pos > start_pos)
current_chunk_size_ = end_pos - start_pos + 1;
}
}
ReadMore();
}
bool DocumentLoader::GetByteRange(const std::string& headers, uint32* start,
uint32* end) {
net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
while (it.GetNext()) {
if (LowerCaseEqualsASCII(it.name(), "content-range")) {
std::string range = it.values().c_str();
if (StartsWithASCII(range, "bytes", false)) {
range = range.substr(strlen("bytes"));
std::string::size_type pos = range.find('-');
std::string range_end;
if (pos != std::string::npos)
range_end = range.substr(pos + 1);
TrimWhitespaceASCII(range, base::TRIM_LEADING, &range);
TrimWhitespaceASCII(range_end, base::TRIM_LEADING, &range_end);
*start = atoi(range.c_str());
*end = atoi(range_end.c_str());
return true;
}
}
}
return false;
}
std::string DocumentLoader::GetMultiPartBoundary(const std::string& headers) {
net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n");
while (it.GetNext()) {
if (LowerCaseEqualsASCII(it.name(), "content-type")) {
std::string type = StringToLowerASCII(it.values());
if (StartsWithASCII(type, "multipart/", true)) {
const char* boundary = strstr(type.c_str(), "boundary=");
if (!boundary) {
NOTREACHED();
break;
}
return std::string(boundary + 9);
}
}
}
return std::string();
}
void DocumentLoader::ReadMore() {
pp::CompletionCallback callback =
loader_factory_.NewCallback(&DocumentLoader::DidRead);
int rv = loader_.ReadResponseBody(buffer_, sizeof(buffer_), callback);
if (rv != PP_OK_COMPLETIONPENDING)
callback.Run(rv);
}
void DocumentLoader::DidRead(int32_t result) {
if (result > 0) {
char* start = buffer_;
size_t length = result;
if (is_multipart_ && result > 2) {
for (int i = 2; i < result; ++i) {
if ((buffer_[i - 1] == '\n' && buffer_[i - 2] == '\n') ||
(i >= 4 &&
buffer_[i - 1] == '\n' && buffer_[i - 2] == '\r' &&
buffer_[i - 3] == '\n' && buffer_[i - 4] == '\r')) {
uint32 start_pos, end_pos;
if (GetByteRange(std::string(buffer_, i), &start_pos, &end_pos)) {
current_pos_ = start_pos;
start += i;
length -= i;
if (end_pos && end_pos > start_pos)
current_chunk_size_ = end_pos - start_pos + 1;
}
break;
}
}
// Reset this flag so we don't look inside the buffer in future calls of
// DidRead for this response. Note that this code DOES NOT handle multi-
// part responses with more than one part (we don't issue them at the
// moment, so they shouldn't arrive).
is_multipart_ = false;
}
if (current_chunk_size_ &&
current_chunk_read_ + length > current_chunk_size_)
length = current_chunk_size_ - current_chunk_read_;
if (length) {
if (document_size_ > 0) {
chunk_stream_.WriteData(current_pos_, start, length);
} else {
// If we did not get content-length in the response, we can't
// preallocate buffer for the entire document. Resizing array causing
// memory fragmentation issues on the large files and OOM exceptions.
// To fix this, we collect all chunks of the file to the list and
// concatenate them together after request is complete.
chunk_buffer_.push_back(std::vector<unsigned char>());
chunk_buffer_.back().resize(length);
memcpy(&(chunk_buffer_.back()[0]), start, length);
}
current_pos_ += length;
current_chunk_read_ += length;
client_->OnNewDataAvailable();
}
ReadMore();
} else if (result == PP_OK) {
ReadComplete();
} else {
NOTREACHED();
}
}
void DocumentLoader::ReadComplete() {
if (!partial_document_) {
if (document_size_ == 0) {
// For the document with no 'content-length" specified we've collected all
// the chunks already. Let's allocate final document buffer and copy them
// over.
chunk_stream_.Preallocate(current_pos_);
uint32 pos = 0;
std::list<std::vector<unsigned char> >::iterator it;
for (it = chunk_buffer_.begin(); it != chunk_buffer_.end(); ++it) {
chunk_stream_.WriteData(pos, &((*it)[0]), it->size());
pos += it->size();
}
chunk_buffer_.clear();
}
document_size_ = current_pos_;
client_->OnDocumentComplete();
return;
}
request_pending_ = false;
pending_requests_.pop_front();
// If there are more pending request - continue downloading.
if (!pending_requests_.empty()) {
DownloadPendingRequests();
return;
}
if (IsDocumentComplete()) {
client_->OnDocumentComplete();
return;
}
if (header_request_)
client_->OnPartialDocumentLoaded();
else
client_->OnPendingRequestComplete();
header_request_ = false;
// The OnPendingRequestComplete could have added more requests.
if (!pending_requests_.empty()) {
DownloadPendingRequests();
} else {
// Document is not complete and we have no outstanding requests.
// Let's keep downloading PDF file in small chunks.
uint32 pos = chunk_stream_.GetFirstMissingByte();
std::vector<std::pair<size_t, size_t> > ranges;
chunk_stream_.GetMissedRanges(pos, GetRequestSize(), &ranges);
DCHECK(ranges.size() > 0);
RequestData(ranges[0].first, ranges[0].second);
}
}
uint32 DocumentLoader::GetRequestSize() const {
std::map<uint32, uint32>::const_iterator iter =
chunk_size_table_.lower_bound(requests_count_);
if (iter == chunk_size_table_.end())
iter--;
return iter->second;
}
} // namespace chrome_pdf

126
pdf/document_loader.h Normal file

@ -0,0 +1,126 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_DOCUMENT_LOADER_H_
#define PDF_DOCUMENT_LOADER_H_
#include <list>
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "pdf/chunk_stream.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/utility/completion_callback_factory.h"
#define kDefaultRequestSize 32768u
namespace chrome_pdf {
class DocumentLoader {
public:
class Client {
public:
// Gets the pp::Instance object.
virtual pp::Instance* GetPluginInstance() = 0;
// Creates new URLLoader based on client settings.
virtual pp::URLLoader CreateURLLoader() = 0;
// Notification called when partial information about document is available.
// Only called for urls that returns full content size and supports byte
// range requests.
virtual void OnPartialDocumentLoaded() = 0;
// Notification called when all outstanding pending requests are complete.
virtual void OnPendingRequestComplete() = 0;
// Notification called when new data is available.
virtual void OnNewDataAvailable() = 0;
// Notification called when document is fully loaded.
virtual void OnDocumentComplete() = 0;
};
explicit DocumentLoader(Client* client);
virtual ~DocumentLoader();
bool Init(const pp::URLLoader& loader,
const std::string& url,
const std::string& headers);
// Data access interface. Return true is sucessful.
bool GetBlock(uint32 position, uint32 size, void* buf) const;
// Data availability interface. Return true data avaialble.
bool IsDataAvailable(uint32 position, uint32 size) const;
// Data availability interface. Return true data avaialble.
void RequestData(uint32 position, uint32 size);
bool IsDocumentComplete() const;
uint32 document_size() const { return document_size_; }
// Return number of bytes available.
uint32 GetAvailableData() const;
// Clear pending requests from the queue.
void ClearPendingRequests();
bool is_partial_document() { return partial_document_; }
private:
// Called by the completion callback of the document's URLLoader.
void DidOpen(int32_t result);
// Call to read data from the document's URLLoader.
void ReadMore();
// Called by the completion callback of the document's URLLoader.
void DidRead(int32_t result);
// If the headers have a byte-range response, writes the start and end
// positions and returns true if at least the start position was parsed.
// The end position will be set to 0 if it was not found or parsed from the
// response.
// Returns false if not even a start position could be parsed.
static bool GetByteRange(const std::string& headers, uint32* start,
uint32* end);
// If the headers have a multi-part response, returns the boundary name.
// Otherwise returns an empty string.
static std::string GetMultiPartBoundary(const std::string& headers);
// Called when we detect that partial document load is possible.
void LoadPartialDocument();
// Called when we have to load full document.
void LoadFullDocument();
// Download pending requests.
void DownloadPendingRequests();
// Called when we complete server request and read all data from it.
void ReadComplete();
// Creates request to download size byte of data data starting from position.
pp::URLRequestInfo GetRequest(uint32 position, uint32 size) const;
// Returns current request size in bytes.
uint32 GetRequestSize() const;
Client* client_;
std::string url_;
pp::URLLoader loader_;
pp::CompletionCallbackFactory<DocumentLoader> loader_factory_;
ChunkStream chunk_stream_;
bool partial_document_;
bool request_pending_;
typedef std::list<std::pair<size_t, size_t> > PendingRequests;
PendingRequests pending_requests_;
char buffer_[kDefaultRequestSize];
uint32 current_pos_;
uint32 current_chunk_size_;
uint32 current_chunk_read_;
uint32 document_size_;
bool header_request_;
bool is_multipart_;
std::string multipart_boundary_;
uint32 requests_count_;
std::map<uint32, uint32> chunk_size_table_;
std::list<std::vector<unsigned char> > chunk_buffer_;
};
} // namespace chrome_pdf
#endif // PDF_DOCUMENT_LOADER_H_

324
pdf/draw_utils.cc Normal file

@ -0,0 +1,324 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/draw_utils.h"
#include <algorithm>
#include <math.h>
#include <vector>
#include "base/logging.h"
namespace chrome_pdf {
inline uint8 GetBlue(const uint32& pixel) {
return static_cast<uint8>(pixel & 0xFF);
}
inline uint8 GetGreen(const uint32& pixel) {
return static_cast<uint8>((pixel >> 8) & 0xFF);
}
inline uint8 GetRed(const uint32& pixel) {
return static_cast<uint8>((pixel >> 16) & 0xFF);
}
inline uint8 GetAlpha(const uint32& pixel) {
return static_cast<uint8>((pixel >> 24) & 0xFF);
}
inline uint32_t MakePixel(uint8 red, uint8 green, uint8 blue, uint8 alpha) {
return (static_cast<uint32_t>(alpha) << 24) |
(static_cast<uint32_t>(red) << 16) |
(static_cast<uint32_t>(green) << 8) |
static_cast<uint32_t>(blue);
}
inline uint8 GradientChannel(uint8 start, uint8 end, double ratio) {
double new_channel = start - (static_cast<double>(start) - end) * ratio;
if (new_channel < 0)
return 0;
if (new_channel > 255)
return 255;
return static_cast<uint8>(new_channel + 0.5);
}
inline uint8 ProcessColor(uint8 src_color, uint8 dest_color, uint8 alpha) {
uint32 processed = static_cast<uint32>(src_color) * alpha +
static_cast<uint32>(dest_color) * (0xFF - alpha);
return static_cast<uint8>((processed / 0xFF) & 0xFF);
}
bool AlphaBlend(const pp::ImageData& src, const pp::Rect& src_rc,
pp::ImageData* dest, const pp::Point& dest_origin,
uint8 alpha_adjustment) {
const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
uint32_t* dest_origin_pixel = dest->GetAddr32(dest_origin);
int height = src_rc.height();
int width = src_rc.width();
for (int y = 0; y < height; y++) {
const uint32_t* src_pixel = src_origin_pixel;
uint32_t* dest_pixel = dest_origin_pixel;
for (int x = 0; x < width; x++) {
uint8 alpha = static_cast<uint8>(static_cast<uint32_t>(alpha_adjustment) *
GetAlpha(*src_pixel) / 0xFF);
uint8 red = ProcessColor(GetRed(*src_pixel), GetRed(*dest_pixel), alpha);
uint8 green = ProcessColor(GetGreen(*src_pixel),
GetGreen(*dest_pixel), alpha);
uint8 blue = ProcessColor(GetBlue(*src_pixel),
GetBlue(*dest_pixel), alpha);
*dest_pixel = MakePixel(red, green, blue, GetAlpha(*dest_pixel));
src_pixel++;
dest_pixel++;
}
src_origin_pixel = reinterpret_cast<const uint32_t*>(
reinterpret_cast<const char*>(src_origin_pixel) + src.stride());
dest_origin_pixel = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
}
return true;
}
void GradientFill(pp::ImageData* image, const pp::Rect& rc,
uint32 start_color, uint32 end_color, bool horizontal) {
std::vector<uint32> colors;
colors.resize(horizontal ? rc.width() : rc.height());
for (size_t i = 0; i < colors.size(); ++i) {
double ratio = static_cast<double>(i) / colors.size();
colors[i] = MakePixel(
GradientChannel(GetRed(start_color), GetRed(end_color), ratio),
GradientChannel(GetGreen(start_color), GetGreen(end_color), ratio),
GradientChannel(GetBlue(start_color), GetBlue(end_color), ratio),
GradientChannel(GetAlpha(start_color), GetAlpha(end_color), ratio));
}
if (horizontal) {
const void* data = &(colors[0]);
size_t size = colors.size() * 4;
uint32_t* origin_pixel = image->GetAddr32(rc.point());
for (int y = 0; y < rc.height(); y++) {
memcpy(origin_pixel, data, size);
origin_pixel = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(origin_pixel) + image->stride());
}
} else {
uint32_t* origin_pixel = image->GetAddr32(rc.point());
for (int y = 0; y < rc.height(); y++) {
uint32_t* pixel = origin_pixel;
for (int x = 0; x < rc.width(); x++) {
*pixel = colors[y];
pixel++;
}
origin_pixel = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(origin_pixel) + image->stride());
}
}
}
void GradientFill(pp::Instance* instance,
pp::ImageData* image,
const pp::Rect& dirty_rc,
const pp::Rect& gradient_rc,
uint32 start_color,
uint32 end_color,
bool horizontal,
uint8 transparency) {
pp::Rect draw_rc = gradient_rc.Intersect(dirty_rc);
if (draw_rc.IsEmpty())
return;
pp::ImageData gradient(instance, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
gradient_rc.size(), false);
GradientFill(&gradient, pp::Rect(pp::Point(), gradient_rc.size()),
start_color, end_color, horizontal);
pp::Rect copy_rc(draw_rc);
copy_rc.Offset(-gradient_rc.x(), -gradient_rc.y());
AlphaBlend(gradient, copy_rc, image, draw_rc.point(), transparency);
}
void CopyImage(const pp::ImageData& src, const pp::Rect& src_rc,
pp::ImageData* dest, const pp::Rect& dest_rc,
bool stretch) {
DCHECK(src_rc.width() <= dest_rc.width() &&
src_rc.height() <= dest_rc.height());
const uint32_t* src_origin_pixel = src.GetAddr32(src_rc.point());
uint32_t* dest_origin_pixel = dest->GetAddr32(dest_rc.point());
if (stretch) {
double x_ratio = static_cast<double>(src_rc.width()) / dest_rc.width();
double y_ratio = static_cast<double>(src_rc.height()) / dest_rc.height();
int height = dest_rc.height();
int width = dest_rc.width();
for (int y = 0; y < height; y++) {
uint32_t* dest_pixel = dest_origin_pixel;
for (int x = 0; x < width; x++) {
uint32 src_x = static_cast<uint32>(x * x_ratio);
uint32 src_y = static_cast<uint32>(y * y_ratio);
const uint32_t* src_pixel = src.GetAddr32(
pp::Point(src_rc.x() + src_x, src_rc.y() + src_y));
*dest_pixel = *src_pixel;
dest_pixel++;
}
dest_origin_pixel = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
}
} else {
int height = src_rc.height();
int width_bytes = src_rc.width() * 4;
for (int y = 0; y < height; y++) {
memcpy(dest_origin_pixel, src_origin_pixel, width_bytes);
src_origin_pixel = reinterpret_cast<const uint32_t*>(
reinterpret_cast<const char*>(src_origin_pixel) + src.stride());
dest_origin_pixel = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(dest_origin_pixel) + dest->stride());
}
}
}
void FillRect(pp::ImageData* image, const pp::Rect& rc, uint32 color) {
int height = rc.height();
if (height == 0)
return;
// Fill in first row.
uint32_t* top_line = image->GetAddr32(rc.point());
int width = rc.width();
for (int x = 0; x < width; x++)
top_line[x] = color;
// Fill in the rest of the rectangle.
int byte_width = width * 4;
uint32_t* cur_line = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(top_line) + image->stride());
for (int y = 1; y < height; y++) {
memcpy(cur_line, top_line, byte_width);
cur_line = reinterpret_cast<uint32_t*>(
reinterpret_cast<char*>(cur_line) + image->stride());
}
}
ShadowMatrix::ShadowMatrix(uint32 depth, double factor, uint32 background)
: depth_(depth), factor_(factor), background_(background) {
DCHECK(depth_ > 0);
matrix_.resize(depth_ * depth_);
// pv - is a rounding power factor for smoothing corners.
// pv = 2.0 will make corners completely round.
const double pv = 4.0;
// pow_pv - cache to avoid recalculating pow(x, pv) every time.
std::vector<double> pow_pv(depth_, 0.0);
double r = static_cast<double>(depth_);
double coef = 256.0 / pow(r, factor);
for (uint32 y = 0; y < depth_; y++) {
// Since matrix is symmetrical, we can reduce the number of calculations
// by mirroring results.
for (uint32 x = 0; x <= y; x++) {
// Fill cache if needed.
if (pow_pv[x] == 0.0)
pow_pv[x] = pow(x, pv);
if (pow_pv[y] == 0.0)
pow_pv[y] = pow(y, pv);
// v - is a value for the smoothing function.
// If x == 0 simplify calculations.
double v = (x == 0) ? y : pow(pow_pv[x] + pow_pv[y], 1 / pv);
// Smoothing function.
// If factor == 1, smoothing will be linear from 0 to the end,
// if 0 < factor < 1, smoothing will drop faster near 0.
// if factor > 1, smoothing will drop faster near the end (depth).
double f = 256.0 - coef * pow(v, factor);
uint8 alpha = 0;
if (f > kOpaqueAlpha)
alpha = kOpaqueAlpha;
else if (f < kTransparentAlpha)
alpha = kTransparentAlpha;
else
alpha = static_cast<uint8>(f);
uint8 red = ProcessColor(0, GetRed(background), alpha);
uint8 green = ProcessColor(0, GetGreen(background), alpha);
uint8 blue = ProcessColor(0, GetBlue(background), alpha);
uint32 pixel = MakePixel(red, green, blue, GetAlpha(background));
// Mirror matrix.
matrix_[y * depth_ + x] = pixel;
matrix_[x * depth_ + y] = pixel;
}
}
}
ShadowMatrix::~ShadowMatrix() {
}
void PaintShadow(pp::ImageData* image,
const pp::Rect& clip_rc,
const pp::Rect& shadow_rc,
const ShadowMatrix& matrix) {
pp::Rect draw_rc = shadow_rc.Intersect(clip_rc);
if (draw_rc.IsEmpty())
return;
int32 depth = static_cast<int32>(matrix.depth());
for (int32_t y = draw_rc.y(); y < draw_rc.bottom(); y++) {
for (int32_t x = draw_rc.x(); x < draw_rc.right(); x++) {
int32_t matrix_x = std::max(depth + shadow_rc.x() - x - 1,
depth - shadow_rc.right() + x);
int32_t matrix_y = std::max(depth + shadow_rc.y() - y - 1,
depth - shadow_rc.bottom() + y);
uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
if (matrix_x < 0)
matrix_x = 0;
else if (matrix_x >= static_cast<int32>(depth))
matrix_x = depth - 1;
if (matrix_y < 0)
matrix_y = 0;
else if (matrix_y >= static_cast<int32>(depth))
matrix_y = depth - 1;
*pixel = matrix.GetValue(matrix_x, matrix_y);
}
}
}
void DrawShadow(pp::ImageData* image,
const pp::Rect& shadow_rc,
const pp::Rect& object_rc,
const pp::Rect& clip_rc,
const ShadowMatrix& matrix) {
if (shadow_rc == object_rc)
return; // Nothing to paint.
// Fill top part.
pp::Rect rc(shadow_rc.point(),
pp::Size(shadow_rc.width(), object_rc.y() - shadow_rc.y()));
PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
// Fill bottom part.
rc = pp::Rect(shadow_rc.x(), object_rc.bottom(),
shadow_rc.width(), shadow_rc.bottom() - object_rc.bottom());
PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
// Fill left part.
rc = pp::Rect(shadow_rc.x(), object_rc.y(),
object_rc.x() - shadow_rc.x(), object_rc.height());
PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
// Fill right part.
rc = pp::Rect(object_rc.right(), object_rc.y(),
shadow_rc.right() - object_rc.right(), object_rc.height());
PaintShadow(image, rc.Intersect(clip_rc), shadow_rc, matrix);
}
} // namespace chrome_pdf

94
pdf/draw_utils.h Normal file

@ -0,0 +1,94 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_DRAW_UTILS_H_
#define PDF_DRAW_UTILS_H_
#include <vector>
#include "base/basictypes.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/rect.h"
namespace chrome_pdf {
const uint8 kOpaqueAlpha = 0xFF;
const uint8 kTransparentAlpha = 0x00;
bool AlphaBlend(const pp::ImageData& src, const pp::Rect& src_rc,
pp::ImageData* dest, const pp::Point& dest_origin,
uint8 alpha_adjustment);
// Fill rectangle with gradient horizontally or vertically. Start is a color of
// top-left point of the rectangle, end color is a color of
// top-right (horizontal==true) or bottom-left (horizontal==false) point.
void GradientFill(pp::ImageData* image,
const pp::Rect& rc,
uint32 start_color,
uint32 end_color,
bool horizontal);
// Fill dirty rectangle with gradient, where gradient color set for corners of
// gradient rectangle. Parts of the dirty rect outside of gradient rect will
// be unchanged.
void GradientFill(pp::Instance* instance,
pp::ImageData* image,
const pp::Rect& dirty_rc,
const pp::Rect& gradient_rc,
uint32 start_color,
uint32 end_color,
bool horizontal,
uint8 transparency);
// Copy one image into another. If stretch is true, the result occupy the entire
// dest_rc. If stretch is false, dest_rc.point will be used as an origin of the
// result image. Copy will ignore all pixels with transparent alpha from the
// source image.
void CopyImage(const pp::ImageData& src, const pp::Rect& src_rc,
pp::ImageData* dest, const pp::Rect& dest_rc,
bool stretch);
// Fill in rectangle with specified color.
void FillRect(pp::ImageData* image, const pp::Rect& rc, uint32 color);
// Shadow Matrix contains matrix for shadow rendering. To reduce amount of
// calculations user may choose to cache matrix and reuse it if nothing changed.
class ShadowMatrix {
public:
// Matrix parameters.
// depth - how big matrix should be. Shadow will go smoothly across the
// entire matrix from black to background color.
// If factor == 1, smoothing will be linear from 0 to the end (depth),
// if 0 < factor < 1, smoothing will drop faster near 0.
// if factor > 1, smoothing will drop faster near the end (depth).
ShadowMatrix(uint32 depth, double factor, uint32 background);
~ShadowMatrix();
uint32 GetValue(int32 x, int32 y) const { return matrix_[y * depth_ + x]; }
uint32 depth() const { return depth_; }
double factor() const { return factor_; }
uint32 background() const { return background_; }
private:
uint32 depth_;
double factor_;
uint32 background_;
std::vector<uint32> matrix_;
};
// Draw shadow on the image using provided ShadowMatrix.
// shadow_rc - rectangle occupied by shadow
// object_rc - rectangle that drops the shadow
// clip_rc - clipping region
void DrawShadow(pp::ImageData* image,
const pp::Rect& shadow_rc,
const pp::Rect& object_rc,
const pp::Rect& clip_rc,
const ShadowMatrix& matrix);
} // namespace chrome_pdf
#endif // PDF_DRAW_UTILS_H_

75
pdf/fading_control.cc Normal file

@ -0,0 +1,75 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/fading_control.h"
#include <math.h>
#include "base/logging.h"
#include "pdf/draw_utils.h"
#include "pdf/resource_consts.h"
namespace chrome_pdf {
FadingControl::FadingControl()
: alpha_shift_(0), timer_id_(0) {
}
FadingControl::~FadingControl() {
}
void FadingControl::OnTimerFired(uint32 timer_id) {
if (timer_id == timer_id_) {
int32 new_alpha = transparency() + alpha_shift_;
if (new_alpha <= kTransparentAlpha) {
Show(false, true);
OnFadeOutComplete();
return;
}
if (new_alpha >= kOpaqueAlpha) {
AdjustTransparency(kOpaqueAlpha, true);
OnFadeInComplete();
return;
}
AdjustTransparency(static_cast<uint8>(new_alpha), true);
timer_id_ = owner()->ScheduleTimer(id(), kFadingTimeoutMs);
}
}
// Fade In/Out control depending on visible flag over the time of time_ms.
void FadingControl::Fade(bool show, uint32 time_ms) {
DCHECK(time_ms != 0);
// Check if we already in the same state.
if (!visible() && !show)
return;
if (!visible() && show) {
Show(show, false);
AdjustTransparency(kTransparentAlpha, false);
OnFadeOutComplete();
}
if (transparency() == kOpaqueAlpha && show) {
OnFadeInComplete();
return;
}
int delta = show ? kOpaqueAlpha - transparency() : transparency();
double shift =
static_cast<double>(delta) * kFadingTimeoutMs / time_ms;
if (shift > delta)
alpha_shift_ = delta;
else
alpha_shift_ = static_cast<int>(ceil(shift));
if (alpha_shift_ == 0)
alpha_shift_ = 1;
// If disabling, make alpha shift negative.
if (!show)
alpha_shift_ = -alpha_shift_;
timer_id_ = owner()->ScheduleTimer(id(), kFadingTimeoutMs);
}
} // namespace chrome_pdf

32
pdf/fading_control.h Normal file

@ -0,0 +1,32 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_FADING_CONTROL_H_
#define PDF_FADING_CONTROL_H_
#include "pdf/control.h"
namespace chrome_pdf {
class FadingControl : public Control {
public:
FadingControl();
virtual ~FadingControl();
virtual void OnTimerFired(uint32 timer_id);
// Fade In/Out control depending on visible flag over the time of time_ms.
virtual void Fade(bool visible, uint32 time_ms);
virtual void OnFadeInComplete() {}
virtual void OnFadeOutComplete() {}
private:
int alpha_shift_;
uint32 timer_id_;
};
} // namespace chrome_pdf
#endif // PDF_FADING_CONTROL_H_

316
pdf/fading_controls.cc Normal file

@ -0,0 +1,316 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/fading_controls.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "pdf/draw_utils.h"
#include "pdf/resource_consts.h"
#include "ppapi/cpp/input_event.h"
namespace chrome_pdf {
const uint32 kFadingAlphaShift = 64;
const uint32 kSplashFadingAlphaShift = 16;
FadingControls::FadingControls()
: state_(NONE), current_transparency_(kOpaqueAlpha), fading_timer_id_(0),
current_capture_control_(kInvalidControlId),
fading_timeout_(kFadingTimeoutMs), alpha_shift_(kFadingAlphaShift),
splash_(false), splash_timeout_(0) {
}
FadingControls::~FadingControls() {
STLDeleteElements(&controls_);
}
bool FadingControls::CreateFadingControls(
uint32 id, const pp::Rect& rc, bool visible,
Control::Owner* owner, uint8 transparency) {
current_transparency_ = transparency;
return Control::Create(id, rc, visible, owner);
}
void FadingControls::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
// When this control is set to invisible the individual controls are not.
// So we need to check for visible() here.
if (!visible())
return;
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
(*iter)->Paint(image_data, rc);
}
}
bool FadingControls::HandleEvent(const pp::InputEvent& event) {
if (!visible())
return false;
pp::MouseInputEvent mouse_event(event);
if (mouse_event.is_null())
return NotifyControls(event);
pp::Point pt = mouse_event.GetPosition();
bool is_mouse_click =
mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN ||
mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP;
if (rect().Contains(pt)) {
CancelSplashMode();
FadeIn();
// Eat mouse click if are invisible or just fading in.
// That prevents accidental clicks on the controls for touch devices.
bool eat_mouse_click =
(state_ == FADING_IN || current_transparency_ == kTransparentAlpha);
if (eat_mouse_click && is_mouse_click &&
mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
return true; // Eat this event here.
}
if ((!rect().Contains(pt)) ||
event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
if (!splash_)
FadeOut();
pp::MouseInputEvent event_leave(pp::MouseInputEvent(
owner()->GetInstance(),
PP_INPUTEVENT_TYPE_MOUSELEAVE,
event.GetTimeStamp(),
event.GetModifiers(),
mouse_event.GetButton(),
mouse_event.GetPosition(),
mouse_event.GetClickCount(),
mouse_event.GetMovement()));
return NotifyControls(event_leave);
}
return NotifyControls(event);
}
void FadingControls::OnTimerFired(uint32 timer_id) {
if (timer_id == fading_timer_id_) {
int32 current_alpha = static_cast<int32>(current_transparency_);
if (state_ == FADING_IN)
current_alpha += alpha_shift_;
else if (state_ == FADING_OUT)
current_alpha -= alpha_shift_;
if (current_alpha >= kOpaqueAlpha) {
state_ = NONE;
current_alpha = kOpaqueAlpha;
} else if (current_alpha <= kTransparentAlpha) {
state_ = NONE;
current_alpha = kTransparentAlpha;
}
current_transparency_ = static_cast<uint8>(current_alpha);
// Invalidate controls with new alpha transparency.
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
// We are going to invalidate the whole FadingControls area, to
// allow simultaneous drawing.
(*iter)->AdjustTransparency(current_transparency_, false);
}
owner()->Invalidate(id(), GetControlsRect());
if (state_ != NONE) // Fading still in progress.
fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
else
OnFadingComplete();
} else {
// Dispatch timer to controls.
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
(*iter)->OnTimerFired(timer_id);
}
}
}
void FadingControls::EventCaptureReleased() {
if (current_capture_control_ != kInvalidControlId) {
// Remove previous catpure.
Control* ctrl = GetControl(current_capture_control_);
if (ctrl)
ctrl->EventCaptureReleased();
}
}
void FadingControls::MoveBy(const pp::Point& offset, bool invalidate) {
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
// We invalidate entire FadingControl later if needed.
(*iter)->MoveBy(offset, false);
}
Control::MoveBy(offset, invalidate);
}
void FadingControls::OnEvent(uint32 control_id, uint32 event_id, void* data) {
owner()->OnEvent(control_id, event_id, data);
}
void FadingControls::Invalidate(uint32 control_id, const pp::Rect& rc) {
owner()->Invalidate(control_id, rc);
}
uint32 FadingControls::ScheduleTimer(uint32 control_id, uint32 timeout_ms) {
// TODO(gene): implement timer routine properly.
NOTIMPLEMENTED();
//owner()->ScheduleTimer(control_id);
return 0;
}
void FadingControls::SetEventCapture(uint32 control_id, bool set_capture) {
if (control_id == current_capture_control_) {
if (!set_capture) // Remove event capture.
current_capture_control_ = kInvalidControlId;
} else {
EventCaptureReleased();
current_capture_control_ = control_id;
}
}
void FadingControls::SetCursor(uint32 control_id,
PP_CursorType_Dev cursor_type) {
owner()->SetCursor(control_id, cursor_type);
}
pp::Instance* FadingControls::GetInstance() {
return owner()->GetInstance();
}
bool FadingControls::AddControl(Control* control) {
DCHECK(control);
if (control->owner() != this)
return false;
if (!rect().Contains(control->rect()))
return false;
control->AdjustTransparency(current_transparency_, false);
controls_.push_back(control);
return true;
}
void FadingControls::RemoveControl(uint32 control_id) {
if (current_capture_control_ == control_id) {
current_capture_control_ = kInvalidControlId;
}
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
if ((*iter)->id() == control_id) {
delete (*iter);
controls_.erase(iter);
break;
}
}
}
Control* FadingControls::GetControl(uint32 id) {
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
if ((*iter)->id() == id)
return *iter;
}
return NULL;
}
pp::Rect FadingControls::GetControlsRect() {
pp::Rect rc;
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
rc = rc.Union((*iter)->rect());
}
return rc;
}
bool FadingControls::ExpandLeft(int offset) {
pp::Rect rc = rect();
rc.set_width(rc.width() + offset);
rc.set_x(rc.x() - offset);
if (!rc.Contains(GetControlsRect()))
return false;
// No need to invalidate since we are expanding triggering area only.
SetRect(rc, false);
return true;
}
void FadingControls::Splash(uint32 time_ms) {
splash_ = true;
splash_timeout_ = time_ms;
alpha_shift_ = kSplashFadingAlphaShift;
FadeIn();
}
bool FadingControls::NotifyControls(const pp::InputEvent& event) {
// First pass event to a control that current capture is set to.
Control* ctrl = GetControl(current_capture_control_);
if (ctrl) {
if (ctrl->HandleEvent(event))
return true;
}
std::list<Control*>::iterator iter;
for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
// Now pass event to all control except control with capture,
// since we already passed to it above.
if ((*iter) != ctrl && (*iter)->HandleEvent(event))
return true;
}
return false;
}
void FadingControls::FadeIn() {
bool already_visible =
(state_ == NONE && current_transparency_ == kOpaqueAlpha);
if (state_ != FADING_IN && !already_visible) {
state_ = FADING_IN;
fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
}
if (already_visible)
OnFadingComplete();
}
void FadingControls::FadeOut() {
bool already_invisible =
(state_ == NONE && current_transparency_ == kTransparentAlpha);
if (state_ != FADING_OUT && !already_invisible) {
state_ = FADING_OUT;
fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
}
if (already_invisible)
OnFadingComplete();
}
void FadingControls::OnFadingComplete() {
DCHECK(current_transparency_ == kOpaqueAlpha ||
current_transparency_ == kTransparentAlpha);
// In the splash mode following states are possible:
// Fade-in complete: splash_==true, splash_timeout_ != 0
// We need to schedule timer for splash_timeout_.
// Splash timeout complete: splash_==true, splash_timeout_ == 0
// We need to fade out still using splash settings.
// Fade-out complete: current_transparency_ == kTransparentAlpha
// We need to cancel splash mode and go back to normal settings.
if (splash_) {
if (current_transparency_ == kOpaqueAlpha) {
if (splash_timeout_) {
fading_timer_id_ = owner()->ScheduleTimer(id(), splash_timeout_);
splash_timeout_ = 0;
} else {
FadeOut();
}
} else {
CancelSplashMode();
}
}
}
void FadingControls::CancelSplashMode() {
splash_ = false;
alpha_shift_ = kFadingAlphaShift;
}
} // namespace chrome_pdf

84
pdf/fading_controls.h Normal file

@ -0,0 +1,84 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_FADING_CONTROLS_H_
#define PDF_FADING_CONTROLS_H_
#include <list>
#include "pdf/control.h"
namespace chrome_pdf {
class FadingControls : public Control,
public ControlOwner {
public:
enum FadingState {
NONE,
FADING_IN,
FADING_OUT
};
FadingControls();
virtual ~FadingControls();
virtual bool CreateFadingControls(
uint32 id, const pp::Rect& rc, bool visible,
Control::Owner* delegate, uint8 transparency);
// Control interface.
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc);
virtual bool HandleEvent(const pp::InputEvent& event);
virtual void OnTimerFired(uint32 timer_id);
virtual void EventCaptureReleased();
virtual void MoveBy(const pp::Point& offset, bool invalidate);
// ControlOwner interface.
virtual void OnEvent(uint32 control_id, uint32 event_id, void* data);
virtual void Invalidate(uint32 control_id, const pp::Rect& rc);
virtual uint32 ScheduleTimer(uint32 control_id, uint32 timeout_ms);
virtual void SetEventCapture(uint32 control_id, bool set_capture);
virtual void SetCursor(uint32 control_id, PP_CursorType_Dev cursor_type);
virtual pp::Instance* GetInstance();
// FadingControls interface
// This function takes ownership of the control, and will destoy it
// when control is destroyed.
// Input control MUST be located inside FadingControls boundaries, and has
// this instance of FadingControls as a delegate.
virtual bool AddControl(Control* control);
virtual void RemoveControl(uint32 control_id);
virtual Control* GetControl(uint32 id);
virtual pp::Rect GetControlsRect();
// Expand/Shrink area which triggers inner control appearance to the left.
virtual bool ExpandLeft(int offset);
// Fade-in, then show controls for time_ms, and then fade-out. Any mouse
// event in this control area will interrupt splash mode.
virtual void Splash(uint32 time_ms);
uint8 current_transparency() const { return current_transparency_; }
private:
bool NotifyControls(const pp::InputEvent& event);
void FadeIn();
void FadeOut();
void OnFadingComplete();
void CancelSplashMode();
std::list<Control*> controls_;
FadingState state_;
uint8 current_transparency_;
uint32 fading_timer_id_;
uint32 current_capture_control_;
uint32 fading_timeout_;
uint32 alpha_shift_;
bool splash_;
uint32 splash_timeout_;
};
} // namespace chrome_pdf
#endif // PDF_FADING_CONTROLS_H_

2719
pdf/instance.cc Normal file

File diff suppressed because it is too large Load Diff

526
pdf/instance.h Normal file

@ -0,0 +1,526 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_INSTANCE_H_
#define PDF_INSTANCE_H_
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "pdf/button.h"
#include "pdf/fading_controls.h"
#include "pdf/page_indicator.h"
#include "pdf/paint_manager.h"
#include "pdf/pdf_engine.h"
#include "pdf/preview_mode_client.h"
#include "pdf/progress_control.h"
#include "pdf/thumbnail_control.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/cpp/dev/printing_dev.h"
#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/dev/scrollbar_dev.h"
#include "ppapi/cpp/dev/selection_dev.h"
#include "ppapi/cpp/dev/widget_client_dev.h"
#include "ppapi/cpp/dev/zoom_dev.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/private/find_private.h"
#include "ppapi/cpp/private/instance_private.h"
#include "ppapi/cpp/private/var_private.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace pp {
class TextInput_Dev;
}
namespace chrome_pdf {
struct ToolbarButtonInfo;
class Instance : public pp::InstancePrivate,
public pp::Find_Private,
public pp::Printing_Dev,
public pp::Selection_Dev,
public pp::WidgetClient_Dev,
public pp::Zoom_Dev,
public PaintManager::Client,
public PDFEngine::Client,
public PreviewModeClient::Client,
public ControlOwner {
public:
explicit Instance(PP_Instance instance);
virtual ~Instance();
// pp::Instance implementation.
virtual bool Init(uint32_t argc,
const char* argn[],
const char* argv[]) OVERRIDE;
virtual bool HandleDocumentLoad(const pp::URLLoader& loader) OVERRIDE;
virtual bool HandleInputEvent(const pp::InputEvent& event) OVERRIDE;
virtual void DidChangeView(const pp::View& view) OVERRIDE;
virtual pp::Var GetInstanceObject() OVERRIDE;
// pp::Find_Private implementation.
virtual bool StartFind(const std::string& text, bool case_sensitive) OVERRIDE;
virtual void SelectFindResult(bool forward) OVERRIDE;
virtual void StopFind() OVERRIDE;
// pp::PaintManager::Client implementation.
virtual void OnPaint(const std::vector<pp::Rect>& paint_rects,
std::vector<PaintManager::ReadyRect>* ready,
std::vector<pp::Rect>* pending) OVERRIDE;
// pp::Printing_Dev implementation.
virtual uint32_t QuerySupportedPrintOutputFormats() OVERRIDE;
virtual int32_t PrintBegin(
const PP_PrintSettings_Dev& print_settings) OVERRIDE;
virtual pp::Resource PrintPages(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count) OVERRIDE;
virtual void PrintEnd() OVERRIDE;
virtual bool IsPrintScalingDisabled() OVERRIDE;
// pp::Private implementation.
virtual pp::Var GetLinkAtPosition(const pp::Point& point);
// PPP_Selection_Dev implementation.
virtual pp::Var GetSelectedText(bool html) OVERRIDE;
// WidgetClient_Dev implementation.
virtual void InvalidateWidget(pp::Widget_Dev widget,
const pp::Rect& dirty_rect) OVERRIDE;
virtual void ScrollbarValueChanged(pp::Scrollbar_Dev scrollbar,
uint32_t value) OVERRIDE;
virtual void ScrollbarOverlayChanged(pp::Scrollbar_Dev scrollbar,
bool overlay) OVERRIDE;
// pp::Zoom_Dev implementation.
virtual void Zoom(double scale, bool text_only) OVERRIDE;
void ZoomChanged(double factor); // Override.
void FlushCallback(int32_t result);
void DidOpen(int32_t result);
void DidOpenPreview(int32_t result);
// If the given widget intersects the rectangle, paints it and adds the
// rect to ready.
void PaintIfWidgetIntersects(pp::Widget_Dev* widget,
const pp::Rect& rect,
std::vector<PaintManager::ReadyRect>* ready,
std::vector<pp::Rect>* pending);
// Called when the timer is fired.
void OnTimerFired(int32_t);
void OnClientTimerFired(int32_t id);
// Called when the control timer is fired.
void OnControlTimerFired(int32_t,
const uint32& control_id,
const uint32& timer_id);
// Called to print without re-entrancy issues.
void OnPrint(int32_t);
// PDFEngine::Client implementation.
virtual void DocumentSizeUpdated(const pp::Size& size);
virtual void Invalidate(const pp::Rect& rect);
virtual void Scroll(const pp::Point& point);
virtual void ScrollToX(int position);
virtual void ScrollToY(int position);
virtual void ScrollToPage(int page);
virtual void NavigateTo(const std::string& url, bool open_in_new_tab);
virtual void UpdateCursor(PP_CursorType_Dev cursor);
virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks);
virtual void NotifyNumberOfFindResultsChanged(int total, bool final_result);
virtual void NotifySelectedFindResultChanged(int current_find_index);
virtual void GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback);
virtual void Alert(const std::string& message);
virtual bool Confirm(const std::string& message);
virtual std::string Prompt(const std::string& question,
const std::string& default_answer);
virtual std::string GetURL();
virtual void Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body);
virtual void Print();
virtual void SubmitForm(const std::string& url,
const void* data,
int length);
virtual std::string ShowFileSelectionDialog();
virtual pp::URLLoader CreateURLLoader();
virtual void ScheduleCallback(int id, int delay_in_ms);
virtual void SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive,
std::vector<SearchStringResult>* results);
virtual void DocumentPaintOccurred();
virtual void DocumentLoadComplete(int page_count);
virtual void DocumentLoadFailed();
virtual pp::Instance* GetPluginInstance();
virtual void DocumentHasUnsupportedFeature(const std::string& feature);
virtual void DocumentLoadProgress(uint32 available, uint32 doc_size);
virtual void FormTextFieldFocusChange(bool in_focus);
virtual bool IsPrintPreview();
// ControlOwner implementation.
virtual void OnEvent(uint32 control_id, uint32 event_id, void* data);
virtual void Invalidate(uint32 control_id, const pp::Rect& rc);
virtual uint32 ScheduleTimer(uint32 control_id, uint32 timeout_ms);
virtual void SetEventCapture(uint32 control_id, bool set_capture);
virtual void SetCursor(uint32 control_id, PP_CursorType_Dev cursor_type);
virtual pp::Instance* GetInstance();
bool dont_paint() const { return dont_paint_; }
void set_dont_paint(bool dont_paint) { dont_paint_ = dont_paint; }
// Called by PDFScriptableObject.
bool HasScriptableMethod(const pp::Var& method, pp::Var* exception);
pp::Var CallScriptableMethod(const pp::Var& method,
const std::vector<pp::Var>& args,
pp::Var* exception);
// PreviewModeClient::Client implementation.
virtual void PreviewDocumentLoadComplete() OVERRIDE;
virtual void PreviewDocumentLoadFailed() OVERRIDE;
// Helper functions for implementing PPP_PDF.
void RotateClockwise();
void RotateCounterclockwise();
private:
// Called whenever the plugin geometry changes to update the location of the
// scrollbars, background parts, and notifies the pdf engine.
void OnGeometryChanged(double old_zoom, float old_device_scale);
void CreateHorizontalScrollbar();
void CreateVerticalScrollbar();
void DestroyHorizontalScrollbar();
void DestroyVerticalScrollbar();
// Returns the thickness of a scrollbar. This returns the thickness when it's
// shown, so for overlay scrollbars it'll still be non-zero.
int GetScrollbarThickness();
// Returns the space we need to reserve for the scrollbar in the plugin area.
// If overlay scrollbars are used, this will be 0.
int GetScrollbarReservedThickness();
// Returns true if overlay scrollbars are in use.
bool IsOverlayScrollbar();
// Figures out the location of any background rectangles (i.e. those that
// aren't painted by the PDF engine).
void CalculateBackgroundParts();
// Computes document width/height in device pixels, based on current zoom and
// device scale
int GetDocumentPixelWidth() const;
int GetDocumentPixelHeight() const;
// Draws a rectangle with the specified dimensions and color in our buffer.
void FillRect(const pp::Rect& rect, unsigned int color);
std::vector<pp::ImageData> GetThumbnailResources();
std::vector<pp::ImageData> GetProgressBarResources(pp::ImageData* background);
void CreateToolbar(const ToolbarButtonInfo* tb_info, size_t size);
int GetToolbarRightOffset();
int GetToolbarBottomOffset();
void CreateProgressBar();
void ConfigureProgressBar();
void CreateThumbnails();
void CreatePageIndicator(bool always_visible);
void ConfigurePageIndicator();
void PaintOverlayControl(Control* ctrl,
pp::ImageData* image_data,
std::vector<PaintManager::ReadyRect>* ready);
void LoadUrl(const std::string& url);
void LoadPreviewUrl(const std::string& url);
void LoadUrlInternal(const std::string& url, pp::URLLoader* loader,
void (Instance::* method)(int32_t));
// Creates a URL loader and allows it to access all urls, i.e. not just the
// frame's origin.
pp::URLLoader CreateURLLoaderInternal();
// Figure out the initial page to display based on #page=N and #nameddest=foo
// in the |url_|.
// Returns -1 if there is no valid fragment. The returned value is 0-based,
// whereas page=N is 1-based.
int GetInitialPage(const std::string& url);
void UpdateToolbarPosition(bool invalidate);
void UpdateProgressBarPosition(bool invalidate);
void UpdatePageIndicatorPosition(bool invalidate);
void FormDidOpen(int32_t result);
std::string GetLocalizedString(PP_ResourceString id);
void UserMetricsRecordAction(const std::string& action);
void SaveAs();
enum ZoomMode {
ZOOM_SCALE, // Standard zooming mode, resize will not affect it.
ZOOM_FIT_TO_WIDTH, // Maintain fit to width on resize.
ZOOM_FIT_TO_PAGE, // Maintain fit to page on resize.
ZOOM_AUTO // Maintain the default auto fitting mode on resize.
};
enum DocumentLoadState {
LOAD_STATE_LOADING,
LOAD_STATE_COMPLETE,
LOAD_STATE_FAILED,
};
// Set new zoom mode and scale. Scale will be ignored if mode != ZOOM_SCALE.
void SetZoom(ZoomMode zoom_mode, double scale);
// Updates internal zoom scale based on the plugin/document geometry and
// current mode.
void UpdateZoomScale();
// Simulates how Chrome "snaps" zooming up/down to the next nearest zoom level
// when the previous zoom level wasn't an integer. We do this so that
// pressing the zoom buttons has the same effect as the menu buttons, even if
// we start from a non-standard zoom level because of fit-width or fit-height.
double CalculateZoom(uint32 control_id) const;
pp::ImageData CreateResourceImage(PP_ResourceImage image_id);
void DrawText(const pp::Point& top_center, PP_ResourceString id);
// Set print preview mode, where the current PDF document is reduced to
// only one page, and then extended to |page_count| pages with
// |page_count| - 1 blank pages.
void SetPrintPreviewMode(int page_count);
// Returns the page number to be displayed in the page indicator. If the
// plugin is running within print preview, the displayed number might be
// different from the index of the displayed page.
int GetPageNumberToDisplay();
// Process the preview page data information. |src_url| specifies the preview
// page data location. The |src_url| is in the format:
// chrome://print/id/page_number/print.pdf
// |dst_page_index| specifies the blank page index that needs to be replaced
// with the new page data.
void ProcessPreviewPageInfo(const std::string& src_url, int dst_page_index);
// Load the next available preview page into the blank page.
void LoadAvailablePreviewPage();
// Enables autoscroll using origin as a neutral (center) point.
void EnableAutoscroll(const pp::Point& origin);
// Disables autoscroll and returns to normal functionality.
void DisableAutoscroll();
// Calculate autoscroll info and return proper mouse pointer and scroll
// andjustments.
PP_CursorType_Dev CalculateAutoscroll(const pp::Point& mouse_pos);
void ConfigureNumberImageGenerator();
NumberImageGenerator* number_image_generator();
int GetScaled(int x) const;
pp::ImageData image_data_;
// Used when the plugin is embedded in a page and we have to create the loader
// ourself.
pp::CompletionCallbackFactory<Instance> loader_factory_;
pp::URLLoader embed_loader_;
pp::URLLoader embed_preview_loader_;
scoped_ptr<pp::Scrollbar_Dev> h_scrollbar_;
scoped_ptr<pp::Scrollbar_Dev> v_scrollbar_;
int32 valid_v_range_;
PP_CursorType_Dev cursor_; // The current cursor.
// Used when selecting and dragging beyond the visible portion, in which case
// we want to scroll the document.
bool timer_pending_;
pp::MouseInputEvent last_mouse_event_;
pp::CompletionCallbackFactory<Instance> timer_factory_;
uint32 current_timer_id_;
// Size, in pixels, of plugin rectangle.
pp::Size plugin_size_;
// Size, in DIPs, of plugin rectangle.
pp::Size plugin_dip_size_;
// Remaining area, in pixels, to render the pdf in after accounting for
// scrollbars/toolbars and horizontal centering.
pp::Rect available_area_;
// Size of entire document in pixels (i.e. if each page is 800 pixels high and
// there are 10 pages, the height will be 8000).
pp::Size document_size_;
double zoom_; // Current zoom factor.
float device_scale_; // Current device scale factor.
bool printing_enabled_;
bool hidpi_enabled_;
// True if the plugin is full-page.
bool full_;
// Zooming mode (none, fit to width, fit to height)
ZoomMode zoom_mode_;
// If true, this means we told the RenderView that we're starting a network
// request so that it can start the throbber. We will tell it again once the
// document finishes loading.
bool did_call_start_loading_;
// Hold off on painting invalidated requests while this flag is true.
bool dont_paint_;
// Indicates if plugin is in autoscroll mode.
bool is_autoscroll_;
// Rect for autoscroll anchor.
pp::Rect autoscroll_rect_;
// Image of the autoscroll anchor and its background.
pp::ImageData autoscroll_anchor_;
// Autoscrolling deltas in pixels.
int autoscroll_x_;
int autoscroll_y_;
// Thickness of a scrollbar.
int scrollbar_thickness_;
// Reserved thickness of a scrollbar. This is how much space the scrollbar
// takes from the available area. 0 for overlay.
int scrollbar_reserved_thickness_;
// Used to remember which toolbar is in use
const ToolbarButtonInfo* current_tb_info_;
size_t current_tb_info_size_;
PaintManager paint_manager_;
struct BackgroundPart {
pp::Rect location;
unsigned int color;
};
std::vector<BackgroundPart> background_parts_;
struct PrintSettings {
PrintSettings() {
Clear();
}
void Clear() {
is_printing = false;
print_pages_called_ = false;
memset(&pepper_print_settings, 0, sizeof(pepper_print_settings));
}
// This is set to true when PrintBegin is called and false when PrintEnd is
// called.
bool is_printing;
// To know whether this was an actual print operation, so we don't double
// count UMA logging.
bool print_pages_called_;
PP_PrintSettings_Dev pepper_print_settings;
};
PrintSettings print_settings_;
scoped_ptr<PDFEngine> engine_;
// This engine is used to render the individual preview page data. This is
// used only in print preview mode. This will use |PreviewModeClient|
// interface which has very limited access to the pp::Instance.
scoped_ptr<PDFEngine> preview_engine_;
std::string url_;
scoped_ptr<FadingControls> toolbar_;
ThumbnailControl thumbnails_;
ProgressControl progress_bar_;
uint32 delayed_progress_timer_id_;
PageIndicator page_indicator_;
// Used for creating images from numbers.
scoped_ptr<NumberImageGenerator> number_image_generator_;
// Used for submitting forms.
pp::CompletionCallbackFactory<Instance> form_factory_;
pp::URLLoader form_loader_;
// Used for printing without re-entrancy issues.
pp::CompletionCallbackFactory<Instance> print_callback_factory_;
// True if we haven't painted the plugin viewport yet.
bool first_paint_;
// True when we've painted at least one page from the document.
bool painted_first_page_;
// True if we should display page indicator, false otherwise
bool show_page_indicator_;
// Callback when the document load completes.
pp::Var on_load_callback_;
pp::Var on_scroll_callback_;
pp::Var on_plugin_size_changed_callback_;
DocumentLoadState document_load_state_;
DocumentLoadState preview_document_load_state_;
// JavaScript interface to control this instance.
// This wraps a PDFScriptableObject in a pp::Var.
pp::VarPrivate instance_object_;
// Used so that we only tell the browser once about an unsupported feature, to
// avoid the infobar going up more than once.
bool told_browser_about_unsupported_feature_;
// Keeps track of which unsupported features we reported, so we avoid spamming
// the stats if a feature shows up many times per document.
std::set<std::string> unsupported_features_reported_;
// Number of pages in print preview mode, 0 if not in print preview mode.
int print_preview_page_count_;
std::vector<int> print_preview_page_numbers_;
// Used to manage loaded print preview page information. A |PreviewPageInfo|
// consists of data source url string and the page index in the destination
// document.
typedef std::pair<std::string, int> PreviewPageInfo;
std::queue<PreviewPageInfo> preview_pages_info_;
// Used to signal the browser about focus changes to trigger the OSK.
// TODO(abodenha@chromium.org) Implement full IME support in the plugin.
// http://crbug.com/132565
scoped_ptr<pp::TextInput_Dev> text_input_;
};
// This implements the JavaScript class entrypoint for the plugin instance.
// This class is just a thin wrapper. It delegates relevant methods to Instance.
class PDFScriptableObject : public pp::deprecated::ScriptableObject {
public:
explicit PDFScriptableObject(Instance* instance);
virtual ~PDFScriptableObject();
// pp::deprecated::ScriptableObject implementation.
virtual bool HasMethod(const pp::Var& method, pp::Var* exception);
virtual pp::Var Call(const pp::Var& method,
const std::vector<pp::Var>& args,
pp::Var* exception);
private:
Instance* instance_;
};
} // namespace chrome_pdf
#endif // PDF_INSTANCE_H_

10
pdf/libpdf.map Normal file

@ -0,0 +1,10 @@
{
global:
GetPDFDocInfo;
PPP_GetInterface;
PPP_InitializeModule;
PPP_ShutdownModule;
RenderPDFPageToBitmap;
local:
*;
};

@ -0,0 +1,81 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/number_image_generator.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "pdf/draw_utils.h"
#include "pdf/instance.h"
namespace chrome_pdf {
const int kPageNumberSeparator = 0;
const int kPageNumberOriginX = 8;
const int kPageNumberOriginY = 4;
NumberImageGenerator::NumberImageGenerator(Instance* instance)
: instance_(instance),
device_scale_(1.0f) {
}
NumberImageGenerator::~NumberImageGenerator() {
}
void NumberImageGenerator::Configure(const pp::ImageData& number_background,
const std::vector<pp::ImageData>& number_images, float device_scale) {
number_background_ = number_background;
number_images_ = number_images;
device_scale_ = device_scale;
}
void NumberImageGenerator::GenerateImage(
int page_number, pp::ImageData* image) {
char buffer[12];
base::snprintf(buffer, sizeof(buffer), "%u", page_number);
int extra_width = 0;
DCHECK(number_images_.size() >= 10);
DCHECK(!number_background_.is_null());
for (size_t i = 1; i < strlen(buffer); ++i) {
int index = buffer[i] - '0';
extra_width += number_images_[index].size().width();
extra_width += static_cast<int>(kPageNumberSeparator * device_scale_);
}
*image = pp::ImageData(
instance_,
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
pp::Size(number_background_.size().width() + extra_width,
number_background_.size().height()),
false);
int stretch_point = number_background_.size().width() / 2;
pp::Rect src_rc(0, 0, stretch_point, number_background_.size().height());
pp::Rect dest_rc(src_rc);
CopyImage(number_background_, src_rc, image, dest_rc, false);
src_rc.Offset(number_background_.size().width() - stretch_point, 0);
dest_rc.Offset(image->size().width() - stretch_point, 0);
CopyImage(number_background_, src_rc, image, dest_rc, false);
src_rc = pp::Rect(stretch_point, 0, 1, number_background_.size().height());
dest_rc = src_rc;
dest_rc.set_width(extra_width + 1);
CopyImage(number_background_, src_rc, image, dest_rc, true);
pp::Point origin(static_cast<int>(kPageNumberOriginX * device_scale_),
static_cast<int>(kPageNumberOriginY * device_scale_));
for (size_t i = 0; i < strlen(buffer); ++i) {
int index = buffer[i] - '0';
CopyImage(
number_images_[index],
pp::Rect(pp::Point(), number_images_[index].size()),
image, pp::Rect(origin, number_images_[index].size()), false);
origin += pp::Point(
number_images_[index].size().width() +
static_cast<int>(kPageNumberSeparator * device_scale_), 0);
}
}
} // namespace chrome_pdf

@ -0,0 +1,37 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_NUMBER_IMAGE_GENERATOR_H
#define PDF_NUMBER_IMAGE_GENERATOR_H
#include <vector>
#include "ppapi/cpp/image_data.h"
namespace chrome_pdf {
class Instance;
class NumberImageGenerator {
public:
explicit NumberImageGenerator(Instance* instance);
virtual ~NumberImageGenerator();
void Configure(const pp::ImageData& number_background,
const std::vector<pp::ImageData>& number_images,
float device_scale);
void GenerateImage(int page_number, pp::ImageData* image);
private:
Instance* instance_;
pp::ImageData number_background_;
std::vector<pp::ImageData> number_images_;
float device_scale_;
};
} // namespace chrome_pdf
#endif // PDF_NUMBER_IMAGE_GENERATOR_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,338 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_OUT_OF_PROCESS_INSTANCE_H_
#define PDF_OUT_OF_PROCESS_INSTANCE_H_
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "pdf/paint_manager.h"
#include "pdf/pdf_engine.h"
#include "pdf/preview_mode_client.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "ppapi/cpp/dev/printing_dev.h"
#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/dev/selection_dev.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/private/find_private.h"
#include "ppapi/cpp/private/instance_private.h"
#include "ppapi/cpp/private/uma_private.h"
#include "ppapi/cpp/private/var_private.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace pp {
class TextInput_Dev;
}
namespace chrome_pdf {
class OutOfProcessInstance : public pp::InstancePrivate,
public pp::Find_Private,
public pp::Printing_Dev,
public pp::Selection_Dev,
public PaintManager::Client,
public PDFEngine::Client,
public PreviewModeClient::Client {
public:
explicit OutOfProcessInstance(PP_Instance instance);
virtual ~OutOfProcessInstance();
// pp::Instance implementation.
virtual bool Init(uint32_t argc,
const char* argn[],
const char* argv[]) OVERRIDE;
virtual void HandleMessage(const pp::Var& message) OVERRIDE;
virtual bool HandleInputEvent(const pp::InputEvent& event) OVERRIDE;
virtual void DidChangeView(const pp::View& view) OVERRIDE;
virtual pp::Var GetInstanceObject() OVERRIDE;
// pp::Find_Private implementation.
virtual bool StartFind(const std::string& text, bool case_sensitive) OVERRIDE;
virtual void SelectFindResult(bool forward) OVERRIDE;
virtual void StopFind() OVERRIDE;
// pp::PaintManager::Client implementation.
virtual void OnPaint(const std::vector<pp::Rect>& paint_rects,
std::vector<PaintManager::ReadyRect>* ready,
std::vector<pp::Rect>* pending) OVERRIDE;
// pp::Printing_Dev implementation.
virtual uint32_t QuerySupportedPrintOutputFormats() OVERRIDE;
virtual int32_t PrintBegin(
const PP_PrintSettings_Dev& print_settings) OVERRIDE;
virtual pp::Resource PrintPages(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count) OVERRIDE;
virtual void PrintEnd() OVERRIDE;
virtual bool IsPrintScalingDisabled() OVERRIDE;
// pp::Private implementation.
virtual pp::Var GetLinkAtPosition(const pp::Point& point);
// PPP_Selection_Dev implementation.
virtual pp::Var GetSelectedText(bool html) OVERRIDE;
void FlushCallback(int32_t result);
void DidOpen(int32_t result);
void DidOpenPreview(int32_t result);
// Called when the timer is fired.
void OnClientTimerFired(int32_t id);
// Called to print without re-entrancy issues.
void OnPrint(int32_t);
// PDFEngine::Client implementation.
virtual void DocumentSizeUpdated(const pp::Size& size);
virtual void Invalidate(const pp::Rect& rect);
virtual void Scroll(const pp::Point& point);
virtual void ScrollToX(int position);
virtual void ScrollToY(int position);
virtual void ScrollToPage(int page);
virtual void NavigateTo(const std::string& url, bool open_in_new_tab);
virtual void UpdateCursor(PP_CursorType_Dev cursor);
virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks);
virtual void NotifyNumberOfFindResultsChanged(int total, bool final_result);
virtual void NotifySelectedFindResultChanged(int current_find_index);
virtual void GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback);
virtual void Alert(const std::string& message);
virtual bool Confirm(const std::string& message);
virtual std::string Prompt(const std::string& question,
const std::string& default_answer);
virtual std::string GetURL();
virtual void Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body);
virtual void Print();
virtual void SubmitForm(const std::string& url,
const void* data,
int length);
virtual std::string ShowFileSelectionDialog();
virtual pp::URLLoader CreateURLLoader();
virtual void ScheduleCallback(int id, int delay_in_ms);
virtual void SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive,
std::vector<SearchStringResult>* results);
virtual void DocumentPaintOccurred();
virtual void DocumentLoadComplete(int page_count);
virtual void DocumentLoadFailed();
virtual pp::Instance* GetPluginInstance();
virtual void DocumentHasUnsupportedFeature(const std::string& feature);
virtual void DocumentLoadProgress(uint32 available, uint32 doc_size);
virtual void FormTextFieldFocusChange(bool in_focus);
virtual bool IsPrintPreview();
// PreviewModeClient::Client implementation.
virtual void PreviewDocumentLoadComplete() OVERRIDE;
virtual void PreviewDocumentLoadFailed() OVERRIDE;
// Helper functions for implementing PPP_PDF.
void RotateClockwise();
void RotateCounterclockwise();
private:
void ResetRecentlySentFindUpdate(int32_t);
// Called whenever the plugin geometry changes to update the location of the
// background parts, and notifies the pdf engine.
void OnGeometryChanged(double old_zoom, float old_device_scale);
// Figures out the location of any background rectangles (i.e. those that
// aren't painted by the PDF engine).
void CalculateBackgroundParts();
// Computes document width/height in device pixels, based on current zoom and
// device scale
int GetDocumentPixelWidth() const;
int GetDocumentPixelHeight() const;
// Draws a rectangle with the specified dimensions and color in our buffer.
void FillRect(const pp::Rect& rect, unsigned int color);
void LoadUrl(const std::string& url);
void LoadPreviewUrl(const std::string& url);
void LoadUrlInternal(const std::string& url, pp::URLLoader* loader,
void (OutOfProcessInstance::* method)(int32_t));
// Creates a URL loader and allows it to access all urls, i.e. not just the
// frame's origin.
pp::URLLoader CreateURLLoaderInternal();
// Figure out the initial page to display based on #page=N and #nameddest=foo
// in the |url_|.
// Returns -1 if there is no valid fragment. The returned value is 0-based,
// whereas page=N is 1-based.
int GetInitialPage(const std::string& url);
void FormDidOpen(int32_t result);
std::string GetLocalizedString(PP_ResourceString id);
void UserMetricsRecordAction(const std::string& action);
enum DocumentLoadState {
LOAD_STATE_LOADING,
LOAD_STATE_COMPLETE,
LOAD_STATE_FAILED,
};
// Set new zoom scale.
void SetZoom(double scale);
// Reduces the document to 1 page and appends |print_preview_page_count_|
// blank pages to the document for print preview.
void AppendBlankPrintPreviewPages();
// Process the preview page data information. |src_url| specifies the preview
// page data location. The |src_url| is in the format:
// chrome://print/id/page_number/print.pdf
// |dst_page_index| specifies the blank page index that needs to be replaced
// with the new page data.
void ProcessPreviewPageInfo(const std::string& src_url, int dst_page_index);
// Load the next available preview page into the blank page.
void LoadAvailablePreviewPage();
pp::ImageData image_data_;
// Used when the plugin is embedded in a page and we have to create the loader
// ourself.
pp::CompletionCallbackFactory<OutOfProcessInstance> loader_factory_;
pp::URLLoader embed_loader_;
pp::URLLoader embed_preview_loader_;
PP_CursorType_Dev cursor_; // The current cursor.
pp::CompletionCallbackFactory<OutOfProcessInstance> timer_factory_;
// Size, in pixels, of plugin rectangle.
pp::Size plugin_size_;
// Size, in DIPs, of plugin rectangle.
pp::Size plugin_dip_size_;
// Remaining area, in pixels, to render the pdf in after accounting for
// horizontal centering.
pp::Rect available_area_;
// Size of entire document in pixels (i.e. if each page is 800 pixels high and
// there are 10 pages, the height will be 8000).
pp::Size document_size_;
double zoom_; // Current zoom factor.
float device_scale_; // Current device scale factor.
bool printing_enabled_;
// True if the plugin is full-page.
bool full_;
PaintManager paint_manager_;
struct BackgroundPart {
pp::Rect location;
unsigned int color;
};
std::vector<BackgroundPart> background_parts_;
struct PrintSettings {
PrintSettings() {
Clear();
}
void Clear() {
is_printing = false;
print_pages_called_ = false;
memset(&pepper_print_settings, 0, sizeof(pepper_print_settings));
}
// This is set to true when PrintBegin is called and false when PrintEnd is
// called.
bool is_printing;
// To know whether this was an actual print operation, so we don't double
// count UMA logging.
bool print_pages_called_;
PP_PrintSettings_Dev pepper_print_settings;
};
PrintSettings print_settings_;
scoped_ptr<PDFEngine> engine_;
// This engine is used to render the individual preview page data. This is
// used only in print preview mode. This will use |PreviewModeClient|
// interface which has very limited access to the pp::Instance.
scoped_ptr<PDFEngine> preview_engine_;
std::string url_;
// Used for submitting forms.
pp::CompletionCallbackFactory<OutOfProcessInstance> form_factory_;
pp::URLLoader form_loader_;
// Used for printing without re-entrancy issues.
pp::CompletionCallbackFactory<OutOfProcessInstance> print_callback_factory_;
// True if we haven't painted the plugin viewport yet.
bool first_paint_;
DocumentLoadState document_load_state_;
DocumentLoadState preview_document_load_state_;
// JavaScript interface to control this instance.
// This wraps a PDFScriptableObject in a pp::Var.
pp::VarPrivate instance_object_;
// A UMA resource for histogram reporting.
pp::UMAPrivate uma_;
// Used so that we only tell the browser once about an unsupported feature, to
// avoid the infobar going up more than once.
bool told_browser_about_unsupported_feature_;
// Keeps track of which unsupported features we reported, so we avoid spamming
// the stats if a feature shows up many times per document.
std::set<std::string> unsupported_features_reported_;
// Number of pages in print preview mode, 0 if not in print preview mode.
int print_preview_page_count_;
std::vector<int> print_preview_page_numbers_;
// Used to manage loaded print preview page information. A |PreviewPageInfo|
// consists of data source url string and the page index in the destination
// document.
typedef std::pair<std::string, int> PreviewPageInfo;
std::queue<PreviewPageInfo> preview_pages_info_;
// Used to signal the browser about focus changes to trigger the OSK.
// TODO(abodenha@chromium.org) Implement full IME support in the plugin.
// http://crbug.com/132565
scoped_ptr<pp::TextInput_Dev> text_input_;
// The last document load progress value sent to the web page.
double last_progress_sent_;
// Whether an update to the number of find results found was sent less than
// |kFindResultCooldownMs| milliseconds ago.
bool recently_sent_find_update_;
// The tickmarks.
std::vector<pp::Rect> tickmarks_;
// Whether the plugin has received a viewport changed message. Nothing should
// be painted until this is received.
bool received_viewport_message_;
// The callback for receiving the password from the page.
scoped_ptr<pp::CompletionCallbackWithOutput<pp::Var> > password_callback_;
};
} // namespace chrome_pdf
#endif // PDF_OUT_OF_PROCESS_INSTANCE_H_

126
pdf/page_indicator.cc Normal file

@ -0,0 +1,126 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/page_indicator.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "pdf/draw_utils.h"
#include "pdf/number_image_generator.h"
#include "pdf/resource_consts.h"
namespace chrome_pdf {
PageIndicator::PageIndicator()
: current_page_(0),
splash_timeout_(kPageIndicatorSplashTimeoutMs),
fade_timeout_(kPageIndicatorScrollFadeTimeoutMs),
always_visible_(false) {
}
PageIndicator::~PageIndicator() {
}
bool PageIndicator::CreatePageIndicator(
uint32 id,
bool visible,
Control::Owner* delegate,
NumberImageGenerator* number_image_generator,
bool always_visible) {
number_image_generator_ = number_image_generator;
always_visible_ = always_visible;
pp::Rect rc;
bool res = Control::Create(id, rc, visible, delegate);
return res;
}
void PageIndicator::Configure(const pp::Point& origin,
const pp::ImageData& background) {
background_ = background;
pp::Rect rc(origin, background_.size());
Control::SetRect(rc, false);
}
void PageIndicator::set_current_page(int current_page) {
if (current_page_ < 0)
return;
current_page_ = current_page;
}
void PageIndicator::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
if (!visible())
return;
pp::Rect draw_rc = rc.Intersect(rect());
if (draw_rc.IsEmpty())
return;
// Copying the background image to a temporary buffer.
pp::ImageData buffer(owner()->GetInstance(), background_.format(),
background_.size(), false);
CopyImage(background_, pp::Rect(background_.size()),
&buffer, pp::Rect(background_.size()), false);
// Creating the page number image.
pp::ImageData page_number_image;
number_image_generator_->GenerateImage(current_page_, &page_number_image);
pp::Point origin2(
(buffer.size().width() - page_number_image.size().width()) / 2.5,
(buffer.size().height() - page_number_image.size().height()) / 2);
// Drawing page number image on the buffer.
if (origin2.x() > 0 && origin2.y() > 0) {
CopyImage(page_number_image,
pp::Rect(pp::Point(), page_number_image.size()),
&buffer,
pp::Rect(origin2, page_number_image.size()),
false);
}
// Drawing the buffer.
pp::Point origin = draw_rc.point();
draw_rc.Offset(-rect().x(), -rect().y());
AlphaBlend(buffer, draw_rc, image_data, origin, transparency());
}
void PageIndicator::OnTimerFired(uint32 timer_id) {
FadingControl::OnTimerFired(timer_id);
if (timer_id == fade_out_timer_id_) {
Fade(false, fade_timeout_);
}
}
void PageIndicator::ResetFadeOutTimer() {
fade_out_timer_id_ =
owner()->ScheduleTimer(id(), splash_timeout_);
}
void PageIndicator::OnFadeInComplete() {
if (!always_visible_)
ResetFadeOutTimer();
}
void PageIndicator::Splash() {
Splash(kPageIndicatorSplashTimeoutMs, kPageIndicatorScrollFadeTimeoutMs);
}
void PageIndicator::Splash(uint32 splash_timeout, uint32 fade_timeout) {
splash_timeout_ = splash_timeout;
fade_timeout_ = fade_timeout;
if (!always_visible_)
fade_out_timer_id_ = 0;
Fade(true, fade_timeout_);
}
int PageIndicator::GetYPosition(
int vertical_scrollbar_y, int document_height, int plugin_height) {
double percent = static_cast<double>(vertical_scrollbar_y) / document_height;
return (plugin_height - rect().height()) * percent;
}
} // namespace chrome_pdf

72
pdf/page_indicator.h Normal file

@ -0,0 +1,72 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PAGE_INDICATOR_H_
#define PDF_PAGE_INDICATOR_H_
#include <string>
#include <vector>
#include "pdf/control.h"
#include "pdf/fading_control.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/point.h"
#include "ppapi/cpp/rect.h"
namespace chrome_pdf {
class NumberImageGenerator;
const uint32 kPageIndicatorScrollFadeTimeoutMs = 240;
const uint32 kPageIndicatorInitialFadeTimeoutMs = 960;
const uint32 kPageIndicatorSplashTimeoutMs = 2000;
class PageIndicator : public FadingControl {
public:
PageIndicator();
virtual ~PageIndicator();
virtual bool CreatePageIndicator(
uint32 id,
bool visible,
Control::Owner* delegate,
NumberImageGenerator* number_image_generator,
bool always_visible);
void Configure(const pp::Point& origin, const pp::ImageData& background);
int current_page() const { return current_page_; }
void set_current_page(int current_page);
virtual void Splash();
void Splash(uint32 splash_timeout, uint32 page_timeout);
// Returns the y position where the page indicator should be drawn given the
// position of the scrollbar and the total document height and the plugin
// height.
int GetYPosition(
int vertical_scrollbar_y, int document_height, int plugin_height);
// Control interface.
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc);
virtual void OnTimerFired(uint32 timer_id);
// FadingControl interface.
virtual void OnFadeInComplete();
private:
void ResetFadeOutTimer();
int current_page_;
pp::ImageData background_;
NumberImageGenerator* number_image_generator_;
uint32 fade_out_timer_id_;
uint32 splash_timeout_;
uint32 fade_timeout_;
bool always_visible_;
};
} // namespace chrome_pdf
#endif // PDF_PAGE_INDICATOR_H_

263
pdf/paint_aggregator.cc Normal file

@ -0,0 +1,263 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/paint_aggregator.h"
#include <algorithm>
#include "base/logging.h"
// ----------------------------------------------------------------------------
// ALGORITHM NOTES
//
// We attempt to maintain a scroll rect in the presence of invalidations that
// are contained within the scroll rect. If an invalidation crosses a scroll
// rect, then we just treat the scroll rect as an invalidation rect.
//
// For invalidations performed prior to scrolling and contained within the
// scroll rect, we offset the invalidation rects to account for the fact that
// the consumer will perform scrolling before painting.
//
// We only support scrolling along one axis at a time. A diagonal scroll will
// therefore be treated as an invalidation.
// ----------------------------------------------------------------------------
PaintAggregator::PaintUpdate::PaintUpdate() {
}
PaintAggregator::PaintUpdate::~PaintUpdate() {
}
PaintAggregator::InternalPaintUpdate::InternalPaintUpdate() :
synthesized_scroll_damage_rect_(false) {
}
PaintAggregator::InternalPaintUpdate::~InternalPaintUpdate() {
}
pp::Rect PaintAggregator::InternalPaintUpdate::GetScrollDamage() const {
// Should only be scrolling in one direction at a time.
DCHECK(!(scroll_delta.x() && scroll_delta.y()));
pp::Rect damaged_rect;
// Compute the region we will expose by scrolling, and paint that into a
// shared memory section.
if (scroll_delta.x()) {
int32_t dx = scroll_delta.x();
damaged_rect.set_y(scroll_rect.y());
damaged_rect.set_height(scroll_rect.height());
if (dx > 0) {
damaged_rect.set_x(scroll_rect.x());
damaged_rect.set_width(dx);
} else {
damaged_rect.set_x(scroll_rect.right() + dx);
damaged_rect.set_width(-dx);
}
} else {
int32_t dy = scroll_delta.y();
damaged_rect.set_x(scroll_rect.x());
damaged_rect.set_width(scroll_rect.width());
if (dy > 0) {
damaged_rect.set_y(scroll_rect.y());
damaged_rect.set_height(dy);
} else {
damaged_rect.set_y(scroll_rect.bottom() + dy);
damaged_rect.set_height(-dy);
}
}
// In case the scroll offset exceeds the width/height of the scroll rect
return scroll_rect.Intersect(damaged_rect);
}
PaintAggregator::PaintAggregator() {
}
bool PaintAggregator::HasPendingUpdate() const {
return !update_.scroll_rect.IsEmpty() || !update_.paint_rects.empty();
}
void PaintAggregator::ClearPendingUpdate() {
update_ = InternalPaintUpdate();
}
PaintAggregator::PaintUpdate PaintAggregator::GetPendingUpdate() {
// Convert the internal paint update to the external one, which includes a
// bit more precomputed info for the caller.
PaintUpdate ret;
ret.scroll_delta = update_.scroll_delta;
ret.scroll_rect = update_.scroll_rect;
ret.has_scroll = ret.scroll_delta.x() != 0 || ret.scroll_delta.y() != 0;
// Include the scroll damage (if any) in the paint rects.
// Code invalidates damaged rect here, it pick it up from the list of paint
// rects in the next block.
if (ret.has_scroll && !update_.synthesized_scroll_damage_rect_) {
update_.synthesized_scroll_damage_rect_ = true;
pp::Rect scroll_damage = update_.GetScrollDamage();
InvalidateRectInternal(scroll_damage, false);
}
ret.paint_rects.reserve(update_.paint_rects.size() + 1);
for (size_t i = 0; i < update_.paint_rects.size(); i++)
ret.paint_rects.push_back(update_.paint_rects[i]);
return ret;
}
void PaintAggregator::SetIntermediateResults(
const std::vector<ReadyRect>& ready,
const std::vector<pp::Rect>& pending) {
update_.ready_rects.insert(
update_.ready_rects.end(), ready.begin(), ready.end());
update_.paint_rects = pending;
}
std::vector<PaintAggregator::ReadyRect> PaintAggregator::GetReadyRects() const {
return update_.ready_rects;
}
void PaintAggregator::InvalidateRect(const pp::Rect& rect) {
InvalidateRectInternal(rect, true);
}
void PaintAggregator::ScrollRect(const pp::Rect& clip_rect,
const pp::Point& amount) {
// We only support scrolling along one axis at a time.
if (amount.x() != 0 && amount.y() != 0) {
InvalidateRect(clip_rect);
return;
}
// We can only scroll one rect at a time.
if (!update_.scroll_rect.IsEmpty() && update_.scroll_rect != clip_rect) {
InvalidateRect(clip_rect);
return;
}
// Again, we only support scrolling along one axis at a time. Make sure this
// update doesn't scroll on a different axis than any existing one.
if ((amount.x() && update_.scroll_delta.y()) ||
(amount.y() && update_.scroll_delta.x())) {
InvalidateRect(clip_rect);
return;
}
// The scroll rect is new or isn't changing (though the scroll amount may
// be changing).
update_.scroll_rect = clip_rect;
update_.scroll_delta += amount;
// We might have just wiped out a pre-existing scroll.
if (update_.scroll_delta == pp::Point()) {
update_.scroll_rect = pp::Rect();
return;
}
// Adjust any paint rects that intersect the scroll. For the portion of the
// paint that is inside the scroll area, move it by the scroll amount and
// replace the existing paint with it. For the portion (if any) that is
// outside the scroll, just invalidate it.
std::vector<pp::Rect> leftover_rects;
for (size_t i = 0; i < update_.paint_rects.size(); ++i) {
if (!update_.scroll_rect.Intersects(update_.paint_rects[i]))
continue;
pp::Rect intersection =
update_.paint_rects[i].Intersect(update_.scroll_rect);
pp::Rect rect = update_.paint_rects[i];
while (!rect.IsEmpty()) {
pp::Rect leftover = rect.Subtract(intersection);
if (leftover.IsEmpty())
break;
// Don't want to call InvalidateRectInternal now since it'll modify
// update_.paint_rects, so keep track of this and do it below.
leftover_rects.push_back(leftover);
rect = rect.Subtract(leftover);
}
update_.paint_rects[i] = ScrollPaintRect(intersection, amount);
// The rect may have been scrolled out of view.
if (update_.paint_rects[i].IsEmpty()) {
update_.paint_rects.erase(update_.paint_rects.begin() + i);
i--;
}
}
for (size_t i = 0; i < leftover_rects.size(); ++i)
InvalidateRectInternal(leftover_rects[i], false);
for (size_t i = 0; i < update_.ready_rects.size(); ++i) {
if (update_.scroll_rect.Contains(update_.ready_rects[i].rect)) {
update_.ready_rects[i].rect =
ScrollPaintRect(update_.ready_rects[i].rect, amount);
}
}
if (update_.synthesized_scroll_damage_rect_) {
pp::Rect damage = update_.GetScrollDamage();
InvalidateRect(damage);
}
}
pp::Rect PaintAggregator::ScrollPaintRect(const pp::Rect& paint_rect,
const pp::Point& amount) const {
pp::Rect result = paint_rect;
result.Offset(amount);
result = update_.scroll_rect.Intersect(result);
return result;
}
void PaintAggregator::InvalidateScrollRect() {
pp::Rect scroll_rect = update_.scroll_rect;
update_.scroll_rect = pp::Rect();
update_.scroll_delta = pp::Point();
InvalidateRect(scroll_rect);
}
void PaintAggregator::InvalidateRectInternal(const pp::Rect& rect_old,
bool check_scroll) {
pp::Rect rect = rect_old;
// Check if any rects that are ready to be painted overlap.
for (size_t i = 0; i < update_.ready_rects.size(); ++i) {
const pp::Rect& existing_rect = update_.ready_rects[i].rect;
if (rect.Intersects(existing_rect)) {
// Re-invalidate in case the union intersects other paint rects.
rect = existing_rect.Union(rect);
update_.ready_rects.erase(update_.ready_rects.begin() + i);
break;
}
}
bool add_paint = true;
// Combine overlapping paints using smallest bounding box.
for (size_t i = 0; i < update_.paint_rects.size(); ++i) {
const pp::Rect& existing_rect = update_.paint_rects[i];
if (existing_rect.Contains(rect)) // Optimize out redundancy.
add_paint = false;
if (rect.Intersects(existing_rect) || rect.SharesEdgeWith(existing_rect)) {
// Re-invalidate in case the union intersects other paint rects.
pp::Rect combined_rect = existing_rect.Union(rect);
update_.paint_rects.erase(update_.paint_rects.begin() + i);
InvalidateRectInternal(combined_rect, check_scroll);
add_paint = false;
}
}
if (add_paint) {
// Add a non-overlapping paint.
update_.paint_rects.push_back(rect);
}
// If the new paint overlaps with a scroll, then also invalidate the rect in
// its new position.
if (check_scroll &&
!update_.scroll_rect.IsEmpty() &&
update_.scroll_rect.Intersects(rect)) {
InvalidateRectInternal(ScrollPaintRect(rect, update_.scroll_delta), false);
}
}

130
pdf/paint_aggregator.h Normal file

@ -0,0 +1,130 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PAINT_AGGREGATOR_H_
#define PDF_PAINT_AGGREGATOR_H_
#include <vector>
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/rect.h"
// This class is responsible for aggregating multiple invalidation and scroll
// commands to produce a scroll and repaint sequence. You can use this manually
// to track your updates, but most applications will use the PaintManager to
// additionally handle the necessary callbacks on top of the PaintAggregator
// functionality.
//
// See http://code.google.com/p/ppapi/wiki/2DPaintingModel
class PaintAggregator {
public:
// Stores information about a rectangle that has finished painting. The
// PaintManager will paint it only when everything else on the screen is also
// ready.
struct ReadyRect {
pp::Point offset;
pp::Rect rect;
pp::ImageData image_data;
};
struct PaintUpdate {
PaintUpdate();
~PaintUpdate();
// True if there is a scroll applied. This indicates that the scroll delta
// and scroll_rect are nonzero (just as a convenience).
bool has_scroll;
// The amount to scroll by. Either the X or Y may be nonzero to indicate a
// scroll in that direction, but there will never be a scroll in both
// directions at the same time (this will be converted to a paint of the
// region instead).
//
// If there is no scroll, this will be (0, 0).
pp::Point scroll_delta;
// The rectangle that should be scrolled by the scroll_delta. If there is no
// scroll, this will be (0, 0, 0, 0). We only track one scroll command at
// once. If there are multiple ones, they will be converted to invalidates.
pp::Rect scroll_rect;
// A list of all the individual dirty rectangles. This is an aggregated list
// of all invalidate calls. Different rectangles may be unified to produce a
// minimal list with no overlap that is more efficient to paint. This list
// also contains the region exposed by any scroll command.
std::vector<pp::Rect> paint_rects;
};
PaintAggregator();
// There is a PendingUpdate if InvalidateRect or ScrollRect were called and
// ClearPendingUpdate was not called.
bool HasPendingUpdate() const;
void ClearPendingUpdate();
PaintUpdate GetPendingUpdate();
// Sets the result of a call to the plugin to paint. This includes rects that
// are finished painting (ready), and ones that are still in-progress
// (pending).
void SetIntermediateResults(const std::vector<ReadyRect>& ready,
const std::vector<pp::Rect>& pending);
// Returns the rectangles that are ready to be painted.
std::vector<ReadyRect> GetReadyRects() const;
// The given rect should be repainted.
void InvalidateRect(const pp::Rect& rect);
// The given rect should be scrolled by the given amounts.
void ScrollRect(const pp::Rect& clip_rect, const pp::Point& amount);
private:
// This structure is an internal version of PaintUpdate. It's different in
// two respects:
//
// - The scroll damange (area exposed by the scroll operation, if any) is
// maintained separately from the dirty rects generated by calling
// InvalidateRect. We need to know this distinction for some operations.
//
// - The paint bounds union is computed on the fly so we don't have to keep
// a rectangle up-to-date as we do different operations.
class InternalPaintUpdate {
public:
InternalPaintUpdate();
~InternalPaintUpdate();
// Computes the rect damaged by scrolling within |scroll_rect| by
// |scroll_delta|. This rect must be repainted. It is not included in
// paint_rects.
pp::Rect GetScrollDamage() const;
pp::Point scroll_delta;
pp::Rect scroll_rect;
// Does not include the scroll damage rect unless
// synthesized_scroll_damage_rect_ is set.
std::vector<pp::Rect> paint_rects;
// Rectangles that are finished painting.
std::vector<ReadyRect> ready_rects;
// Whether we have added the scroll damage rect to paint_rects yet or not.
bool synthesized_scroll_damage_rect_;
};
pp::Rect ScrollPaintRect(const pp::Rect& paint_rect,
const pp::Point& amount) const;
void InvalidateScrollRect();
// Internal method used by InvalidateRect. If |check_scroll| is true, then the
// method checks if there's a pending scroll and if so also invalidates |rect|
// in the new scroll position.
void InvalidateRectInternal(const pp::Rect& rect, bool check_scroll);
InternalPaintUpdate update_;
};
#endif // PDF_PAINT_AGGREGATOR_H_

296
pdf/paint_manager.cc Normal file

@ -0,0 +1,296 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/paint_manager.h"
#include <algorithm>
#include "base/logging.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
PaintManager::PaintManager(pp::Instance* instance,
Client* client,
bool is_always_opaque)
: instance_(instance),
client_(client),
is_always_opaque_(is_always_opaque),
callback_factory_(NULL),
manual_callback_pending_(false),
flush_pending_(false),
has_pending_resize_(false),
graphics_need_to_be_bound_(false),
pending_device_scale_(1.0),
device_scale_(1.0),
in_paint_(false),
first_paint_(true),
view_size_changed_waiting_for_paint_(false) {
// Set the callback object outside of the initializer list to avoid a
// compiler warning about using "this" in an initializer list.
callback_factory_.Initialize(this);
// You can not use a NULL client pointer.
DCHECK(client);
}
PaintManager::~PaintManager() {
}
// static
pp::Size PaintManager::GetNewContextSize(const pp::Size& current_context_size,
const pp::Size& plugin_size) {
// The number of additional space in pixels to allocate to the right/bottom
// of the context.
const int kBufferSize = 100;
// Default to returning the same size.
pp::Size result = current_context_size;
pp::Size min_size(std::max(current_context_size.width() - kBufferSize, 0),
std::max(current_context_size.height() - kBufferSize, 0));
// If the plugin size is bigger than the current context size, we need to
// resize the context. If the plugin size is smaller than the current
// context size by a given threshhold then resize the context so that we
// aren't wasting too much memory.
if (plugin_size.width() > current_context_size.width() ||
plugin_size.height() > current_context_size.height() ||
plugin_size.width() < min_size.width() ||
plugin_size.height() < min_size.height()) {
// Create a larger context than needed so that if we only resize by a
// small margin, we don't need a new context.
result = pp::Size(plugin_size.width() + kBufferSize,
plugin_size.height() + kBufferSize);
}
return result;
}
void PaintManager::Initialize(pp::Instance* instance,
Client* client,
bool is_always_opaque) {
DCHECK(!instance_ && !client_); // Can't initialize twice.
instance_ = instance;
client_ = client;
is_always_opaque_ = is_always_opaque;
}
void PaintManager::SetSize(const pp::Size& new_size, float device_scale) {
if (GetEffectiveSize() == new_size &&
GetEffectiveDeviceScale() == device_scale)
return;
has_pending_resize_ = true;
pending_size_ = new_size;
pending_device_scale_ = device_scale;
view_size_changed_waiting_for_paint_ = true;
Invalidate();
}
void PaintManager::Invalidate() {
// You must call SetSize before using.
DCHECK(!graphics_.is_null() || has_pending_resize_);
EnsureCallbackPending();
aggregator_.InvalidateRect(pp::Rect(GetEffectiveSize()));
}
void PaintManager::InvalidateRect(const pp::Rect& rect) {
DCHECK(!in_paint_);
// You must call SetSize before using.
DCHECK(!graphics_.is_null() || has_pending_resize_);
// Clip the rect to the device area.
pp::Rect clipped_rect = rect.Intersect(pp::Rect(GetEffectiveSize()));
if (clipped_rect.IsEmpty())
return; // Nothing to do.
EnsureCallbackPending();
aggregator_.InvalidateRect(clipped_rect);
}
void PaintManager::ScrollRect(const pp::Rect& clip_rect,
const pp::Point& amount) {
DCHECK(!in_paint_);
// You must call SetSize before using.
DCHECK(!graphics_.is_null() || has_pending_resize_);
EnsureCallbackPending();
aggregator_.ScrollRect(clip_rect, amount);
}
pp::Size PaintManager::GetEffectiveSize() const {
return has_pending_resize_ ? pending_size_ : plugin_size_;
}
float PaintManager::GetEffectiveDeviceScale() const {
return has_pending_resize_ ? pending_device_scale_ : device_scale_;
}
void PaintManager::EnsureCallbackPending() {
// The best way for us to do the next update is to get a notification that
// a previous one has completed. So if we're already waiting for one, we
// don't have to do anything differently now.
if (flush_pending_)
return;
// If no flush is pending, we need to do a manual call to get back to the
// main thread. We may have one already pending, or we may need to schedule.
if (manual_callback_pending_)
return;
pp::Module::Get()->core()->CallOnMainThread(
0,
callback_factory_.NewCallback(&PaintManager::OnManualCallbackComplete),
0);
manual_callback_pending_ = true;
}
void PaintManager::DoPaint() {
in_paint_ = true;
std::vector<ReadyRect> ready;
std::vector<pp::Rect> pending;
DCHECK(aggregator_.HasPendingUpdate());
// Apply any pending resize. Setting the graphics to this class must happen
// before asking the plugin to paint in case it requests invalides or resizes.
// However, the bind must not happen until afterward since we don't want to
// have an unpainted device bound. The needs_binding flag tells us whether to
// do this later.
if (has_pending_resize_) {
plugin_size_ = pending_size_;
// Only create a new graphics context if the current context isn't big
// enough or if it is far too big. This avoids creating a new context if
// we only resize by a small amount.
pp::Size new_size = GetNewContextSize(graphics_.size(), pending_size_);
if (graphics_.size() != new_size) {
graphics_ = pp::Graphics2D(instance_, new_size, is_always_opaque_);
graphics_need_to_be_bound_ = true;
// Since we're binding a new one, all of the callbacks have been canceled.
manual_callback_pending_ = false;
flush_pending_ = false;
callback_factory_.CancelAll();
}
if (pending_device_scale_ != 1.0)
graphics_.SetScale(1.0 / pending_device_scale_);
device_scale_ = pending_device_scale_;
// This must be cleared before calling into the plugin since it may do
// additional invalidation or sizing operations.
has_pending_resize_ = false;
pending_size_ = pp::Size();
}
PaintAggregator::PaintUpdate update = aggregator_.GetPendingUpdate();
client_->OnPaint(update.paint_rects, &ready, &pending);
if (ready.empty() && pending.empty()) {
in_paint_ = false;
return; // Nothing was painted, don't schedule a flush.
}
std::vector<PaintAggregator::ReadyRect> ready_now;
if (pending.empty()) {
std::vector<PaintAggregator::ReadyRect> temp_ready;
for (size_t i = 0; i < ready.size(); ++i)
temp_ready.push_back(ready[i]);
aggregator_.SetIntermediateResults(temp_ready, pending);
ready_now = aggregator_.GetReadyRects();
aggregator_.ClearPendingUpdate();
// Apply any scroll first.
if (update.has_scroll)
graphics_.Scroll(update.scroll_rect, update.scroll_delta);
view_size_changed_waiting_for_paint_ = false;
} else {
std::vector<PaintAggregator::ReadyRect> ready_later;
for (size_t i = 0; i < ready.size(); ++i) {
// Don't flush any part (i.e. scrollbars) if we're resizing the browser,
// as that'll lead to flashes. Until we flush, the browser will use the
// previous image, but if we flush, it'll revert to using the blank image.
// We make an exception for the first paint since we want to show the
// default background color instead of the pepper default of black.
if (ready[i].flush_now &&
(!view_size_changed_waiting_for_paint_ || first_paint_)) {
ready_now.push_back(ready[i]);
} else {
ready_later.push_back(ready[i]);
}
}
// Take the rectangles, except the ones that need to be flushed right away,
// and save them so that everything is flushed at once.
aggregator_.SetIntermediateResults(ready_later, pending);
if (ready_now.empty()) {
in_paint_ = false;
EnsureCallbackPending();
return;
}
}
for (size_t i = 0; i < ready_now.size(); ++i) {
graphics_.PaintImageData(
ready_now[i].image_data, ready_now[i].offset, ready_now[i].rect);
}
int32_t result = graphics_.Flush(
callback_factory_.NewCallback(&PaintManager::OnFlushComplete));
// If you trigger this assertion, then your plugin has called Flush()
// manually. When using the PaintManager, you should not call Flush, it will
// handle that for you because it needs to know when it can do the next paint
// by implementing the flush callback.
//
// Another possible cause of this assertion is re-using devices. If you
// use one device, swap it with another, then swap it back, we won't know
// that we've already scheduled a Flush on the first device. It's best to not
// re-use devices in this way.
DCHECK(result != PP_ERROR_INPROGRESS);
if (result == PP_OK_COMPLETIONPENDING) {
flush_pending_ = true;
} else {
DCHECK(result == PP_OK); // Catch all other errors in debug mode.
}
in_paint_ = false;
first_paint_ = false;
if (graphics_need_to_be_bound_) {
instance_->BindGraphics(graphics_);
graphics_need_to_be_bound_ = false;
}
}
void PaintManager::OnFlushComplete(int32_t) {
DCHECK(flush_pending_);
flush_pending_ = false;
// If more paints were enqueued while we were waiting for the flush to
// complete, execute them now.
if (aggregator_.HasPendingUpdate())
DoPaint();
}
void PaintManager::OnManualCallbackComplete(int32_t) {
DCHECK(manual_callback_pending_);
manual_callback_pending_ = false;
// Just because we have a manual callback doesn't mean there are actually any
// invalid regions. Even though we only schedule this callback when something
// is pending, a Flush callback could have come in before this callback was
// executed and that could have cleared the queue.
if (aggregator_.HasPendingUpdate())
DoPaint();
}

205
pdf/paint_manager.h Normal file

@ -0,0 +1,205 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PAINT_MANAGER_H_
#define PDF_PAINT_MANAGER_H_
#include <vector>
#include "pdf/paint_aggregator.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace pp {
class Graphics2D;
class Instance;
class Point;
class Rect;
};
// Custom PaintManager for the PDF plugin. This is branched from the Pepper
// version. The difference is that this supports progressive rendering of dirty
// rects, where multiple calls to the rendering engine are needed. It also
// supports having higher-priority rects flushing right away, i.e. the
// scrollbars.
//
// The client's OnPaint
class PaintManager {
public:
// Like PaintAggregator's version, but allows the plugin to tell us whether
// it should be flushed to the screen immediately or when the rest of the
// plugin viewport is ready.
struct ReadyRect {
pp::Point offset;
pp::Rect rect;
pp::ImageData image_data;
bool flush_now;
ReadyRect(const pp::Rect& r, const pp::ImageData& i, bool f)
: rect(r), image_data(i), flush_now(f) {}
operator PaintAggregator::ReadyRect() const {
PaintAggregator::ReadyRect rv;
rv.offset = offset;
rv.rect = rect;
rv.image_data = image_data;
return rv;
}
};
class Client {
public:
// Paints the given invalid area of the plugin to the given graphics
// device. Returns true if anything was painted.
//
// You are given the list of rects to paint in |paint_rects|. You can
// combine painting into less rectangles if it's more efficient. When a
// rect is painted, information about that paint should be inserted into
// |ready|. Otherwise if a paint needs more work, add the rect to
// |pending|. If |pending| is not empty, your OnPaint function will get
// called again. Once OnPaint is called and it returns no pending rects,
// all the previously ready rects will be flushed on screen. The exception
// is for ready rects that have |flush_now| set to true. These will be
// flushed right away.
//
// Do not call Flush() on the graphics device, this will be done
// automatically if you return true from this function since the
// PaintManager needs to handle the callback.
//
// Calling Invalidate/Scroll is not allowed while inside an OnPaint
virtual void OnPaint(const std::vector<pp::Rect>& paint_rects,
std::vector<ReadyRect>* ready,
std::vector<pp::Rect>* pending) = 0;
protected:
// You shouldn't be doing deleting through this interface.
virtual ~Client() {}
};
// The instance is the plugin instance using this paint manager to do its
// painting. Painting will automatically go to this instance and you don't
// have to manually bind any device context (this is all handled by the
// paint manager).
//
// The Client is a non-owning pointer and must remain valid (normally the
// object implementing the Client interface will own the paint manager).
//
// The is_always_opaque flag will be passed to the device contexts that this
// class creates. Set this to true if your plugin always draws an opaque
// image to the device. This is used as a hint to the browser that it does
// not need to do alpha blending, which speeds up painting. If you generate
// non-opqaue pixels or aren't sure, set this to false for more general
// blending.
//
// If you set is_always_opaque, your alpha channel should always be set to
// 0xFF or there may be painting artifacts. Being opaque will allow the
// browser to do a memcpy rather than a blend to paint the plugin, and this
// means your alpha values will get set on the page backing store. If these
// values are incorrect, it could mess up future blending. If you aren't
// sure, it is always correct to specify that it it not opaque.
//
// You will need to call SetSize before this class will do anything. Normally
// you do this from the ViewChanged method of your plugin instance.
PaintManager(pp::Instance* instance, Client* client, bool is_always_opaque);
~PaintManager();
// Returns the size of the graphics context to allocate for a given plugin
// size. We may allocated a slightly larger buffer than required so that we
// don't have to resize the context when scrollbars appear/dissapear due to
// zooming (which can result in flickering).
static pp::Size GetNewContextSize(const pp::Size& current_context_size,
const pp::Size& plugin_size);
// You must call this function before using if you use the 0-arg constructor.
// See the constructor for what these arguments mean.
void Initialize(pp::Instance* instance, Client* client,
bool is_always_opaque);
// Sets the size of the plugin. If the size is the same as the previous call,
// this will be a NOP. If the size has changed, a new device will be
// allocated to the given size and a paint to that device will be scheduled.
//
// This is intended to be called from ViewChanged with the size of the
// plugin. Since it tracks the old size and only allocates when the size
// changes, you can always call this function without worrying about whether
// the size changed or ViewChanged is called for another reason (like the
// position changed).
void SetSize(const pp::Size& new_size, float new_device_scale);
// Invalidate the entire plugin.
void Invalidate();
// Invalidate the given rect.
void InvalidateRect(const pp::Rect& rect);
// The given rect should be scrolled by the given amounts.
void ScrollRect(const pp::Rect& clip_rect, const pp::Point& amount);
// Returns the size of the graphics context for the next paint operation.
// This is the pending size if a resize is pending (the plugin has called
// SetSize but we haven't actually painted it yet), or the current size of
// no resize is pending.
pp::Size GetEffectiveSize() const;
float GetEffectiveDeviceScale() const;
private:
// Disallow copy and assign (these are unimplemented).
PaintManager(const PaintManager&);
PaintManager& operator=(const PaintManager&);
// Makes sure there is a callback that will trigger a paint at a later time.
// This will be either a Flush callback telling us we're allowed to generate
// more data, or, if there's no flush callback pending, a manual call back
// to the message loop via ExecuteOnMainThread.
void EnsureCallbackPending();
// Does the client paint and executes a Flush if necessary.
void DoPaint();
// Callback for asynchronous completion of Flush.
void OnFlushComplete(int32_t);
// Callback for manual scheduling of paints when there is no flush callback
// pending.
void OnManualCallbackComplete(int32_t);
pp::Instance* instance_;
// Non-owning pointer. See the constructor.
Client* client_;
bool is_always_opaque_;
pp::CompletionCallbackFactory<PaintManager> callback_factory_;
// This graphics device will be is_null() if no graphics has been manually
// set yet.
pp::Graphics2D graphics_;
PaintAggregator aggregator_;
// See comment for EnsureCallbackPending for more on how these work.
bool manual_callback_pending_;
bool flush_pending_;
// When we get a resize, we don't bind right away (see SetSize). The
// has_pending_resize_ tells us that we need to do a resize for the next
// paint operation. When true, the new size is in pending_size_.
bool has_pending_resize_;
bool graphics_need_to_be_bound_;
pp::Size pending_size_;
pp::Size plugin_size_;
float pending_device_scale_;
float device_scale_;
// True iff we're in the middle of a paint.
bool in_paint_;
// True if we haven't painted the plugin viewport yet.
bool first_paint_;
// True when the view size just changed and we're waiting for a paint.
bool view_size_changed_waiting_for_paint_;
};
#endif // PDF_PAINT_MANAGER_H_

244
pdf/pdf.cc Normal file

@ -0,0 +1,244 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdf.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#include "base/command_line.h"
#include "base/logging.h"
#include "pdf/instance.h"
#include "pdf/out_of_process_instance.h"
#include "ppapi/c/ppp.h"
#include "ppapi/cpp/private/pdf.h"
bool g_sdk_initialized_via_pepper = false;
// The Mac release builds discard CreateModule and the entire PDFModule
// definition because they are not referenced here. This causes the Pepper
// exports (PPP_GetInterface etc) to not be exported. So we force the linker
// to include this code by using __attribute__((used)).
#if __GNUC__ >= 4
#define PDF_USED __attribute__((used))
#else
#define PDF_USED
#endif
#if defined(OS_WIN)
HMODULE g_hmodule;
void HandleInvalidParameter(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t reserved) {
// Do the same as Chrome's CHECK(false) which is undefined.
::base::debug::BreakDebugger();
return;
}
void HandlePureVirtualCall() {
// Do the same as Chrome's CHECK(false) which is undefined.
::base::debug::BreakDebugger();
return;
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason_for_call, LPVOID reserved) {
g_hmodule = module;
if (reason_for_call == DLL_PROCESS_ATTACH) {
// On windows following handlers work only inside module. So breakpad in
// chrome.dll does not catch that. To avoid linking related code or
// duplication breakpad_win.cc::InitCrashReporter() just catch errors here
// and crash in a way interceptable by breakpad of parent module.
_set_invalid_parameter_handler(HandleInvalidParameter);
_set_purecall_handler(HandlePureVirtualCall);
}
return TRUE;
}
#endif
namespace pp {
PDF_USED Module* CreateModule() {
return new chrome_pdf::PDFModule();
}
} // namespace pp
namespace chrome_pdf {
PDFModule::PDFModule() {
}
PDFModule::~PDFModule() {
if (g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
g_sdk_initialized_via_pepper = false;
}
}
bool PDFModule::Init() {
return true;
}
pp::Instance* PDFModule::CreateInstance(PP_Instance instance) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return NULL;
g_sdk_initialized_via_pepper = true;
}
if (pp::PDF::IsOutOfProcess(pp::InstanceHandle(instance)))
return new OutOfProcessInstance(instance);
return new Instance(instance);
}
} // namespace chrome_pdf
extern "C" {
// TODO(sanjeevr): It might make sense to provide more stateful wrappers over
// the internal PDF SDK (such as LoadDocument, LoadPage etc). Determine if we
// need to provide this.
// Wrapper exports over the PDF engine that can be used by an external module
// such as Chrome (since Chrome cannot directly pull in PDFium sources).
#if defined(OS_WIN)
// |pdf_buffer| is the buffer that contains the entire PDF document to be
// rendered.
// |buffer_size| is the size of pdf_buffer in bytes.
// |page_number| is the 0-based index of the page to be rendered.
// |dc| is the device context to render into.
// |dpi_x| and |dpi_y| are the x and y resolutions respectively. If either value
// is -1, the dpi from the DC will be used.
// |bounds_origin_x|, |bounds_origin_y|, |bounds_width| and |bounds_height|
// specify a bounds rectangle within the DC in which to render the PDF page.
// |fit_to_bounds| specifies whether the output should be shrunk to fit the
// supplied bounds if the page size is larger than the bounds in any
// dimension. If this is false, parts of the PDF page that lie outside the
// bounds will be clipped.
// |stretch_to_bounds| specifies whether the output should be stretched to fit
// the supplied bounds if the page size is smaller than the bounds in any
// dimension.
// If both |fit_to_bounds| and |stretch_to_bounds| are true, then
// |fit_to_bounds| is honored first.
// |keep_aspect_ratio| If any scaling is to be done is true, this flag specifies
// whether the original aspect ratio of the page should be preserved while
// scaling.
// |center_in_bounds| specifies whether the final image (after any scaling is
// done) should be centered within the given bounds.
// |autorotate| specifies whether the final image should be rotated to match
// the output bound.
// Returns false if the document or the page number are not valid.
PP_EXPORT bool RenderPDFPageToDC(const void* pdf_buffer,
int buffer_size,
int page_number,
HDC dc,
int dpi_x,
int dpi_y,
int bounds_origin_x,
int bounds_origin_y,
int bounds_width,
int bounds_height,
bool fit_to_bounds,
bool stretch_to_bounds,
bool keep_aspect_ratio,
bool center_in_bounds,
bool autorotate) {
if (!g_sdk_initialized_via_pepper) {
if (!chrome_pdf::InitializeSDK(g_hmodule)) {
return false;
}
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
chrome_pdf::PDFEngineExports::RenderingSettings settings(
dpi_x, dpi_y, pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width,
bounds_height),
fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
autorotate);
bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
page_number, settings, dc);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
#endif // OS_WIN
// |page_count| and |max_page_width| are optional and can be NULL.
// Returns false if the document is not valid.
PDF_USED PP_EXPORT
bool GetPDFDocInfo(const void* pdf_buffer,
int buffer_size, int* page_count,
double* max_page_width) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return false;
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
bool ret = engine_exports->GetPDFDocInfo(
pdf_buffer, buffer_size, page_count, max_page_width);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
// Renders PDF page into 4-byte per pixel BGRA color bitmap.
// |pdf_buffer| is the buffer that contains the entire PDF document to be
// rendered.
// |pdf_buffer_size| is the size of pdf_buffer in bytes.
// |page_number| is the 0-based index of the page to be rendered.
// |bitmap_buffer| is the output buffer for bitmap.
// |bitmap_width| is the width of the output bitmap.
// |bitmap_height| is the height of the output bitmap.
// |dpi| is the resolutions.
// |autorotate| specifies whether the final image should be rotated to match
// the output bound.
// Returns false if the document or the page number are not valid.
PDF_USED PP_EXPORT
bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,
int page_number,
void* bitmap_buffer,
int bitmap_width,
int bitmap_height,
int dpi,
bool autorotate) {
if (!g_sdk_initialized_via_pepper) {
void* data = NULL;
#if defined(OS_WIN)
data = g_hmodule;
#endif
if (!chrome_pdf::InitializeSDK(data))
return false;
}
scoped_ptr<chrome_pdf::PDFEngineExports> engine_exports(
chrome_pdf::PDFEngineExports::Create());
chrome_pdf::PDFEngineExports::RenderingSettings settings(
dpi, dpi, pp::Rect(bitmap_width, bitmap_height), true, false, true, true,
autorotate);
bool ret = engine_exports->RenderPDFPageToBitmap(
pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer);
if (!g_sdk_initialized_via_pepper) {
chrome_pdf::ShutdownSDK();
}
return ret;
}
} // extern "C"

7
pdf/pdf.def Normal file

@ -0,0 +1,7 @@
LIBRARY pdf
EXPORTS
NP_GetEntryPoints @1
NP_Initialize @2
NP_Shutdown @3

181
pdf/pdf.gyp Normal file

@ -0,0 +1,181 @@
{
'variables': {
'chromium_code': 1,
'pdf_engine%': 0, # 0 PDFium
},
'target_defaults': {
'cflags': [
'-fPIC',
],
},
'targets': [
{
'target_name': 'pdf',
'type': 'loadable_module',
'msvs_guid': '647863C0-C7A3-469A-B1ED-AD7283C34BED',
'dependencies': [
'../base/base.gyp:base',
'../net/net.gyp:net',
'../ppapi/ppapi.gyp:ppapi_cpp',
'../third_party/pdfium/pdfium.gyp:fpdfsdk',
],
'xcode_settings': {
'INFOPLIST_FILE': 'Info.plist',
},
'mac_framework_dirs': [
'$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework/Frameworks',
],
'ldflags': [ '-L<(PRODUCT_DIR)',],
'sources': [
'button.h',
'button.cc',
'chunk_stream.h',
'chunk_stream.cc',
'control.h',
'control.cc',
'document_loader.h',
'document_loader.cc',
'draw_utils.cc',
'draw_utils.h',
'fading_control.cc',
'fading_control.h',
'fading_controls.cc',
'fading_controls.h',
'instance.cc',
'instance.h',
'number_image_generator.cc',
'number_image_generator.h',
'out_of_process_instance.cc',
'out_of_process_instance.h',
'page_indicator.cc',
'page_indicator.h',
'paint_aggregator.cc',
'paint_aggregator.h',
'paint_manager.cc',
'paint_manager.h',
'pdf.cc',
'pdf.h',
'pdf.rc',
'progress_control.cc',
'progress_control.h',
'pdf_engine.h',
'preview_mode_client.cc',
'preview_mode_client.h',
'resource.h',
'resource_consts.h',
'thumbnail_control.cc',
'thumbnail_control.h',
'../chrome/browser/chrome_page_zoom_constants.cc',
'../content/common/page_zoom.cc',
],
'conditions': [
['pdf_engine==0', {
'sources': [
'pdfium/pdfium_assert_matching_enums.cc',
'pdfium/pdfium_engine.cc',
'pdfium/pdfium_engine.h',
'pdfium/pdfium_mem_buffer_file_read.cc',
'pdfium/pdfium_mem_buffer_file_read.h',
'pdfium/pdfium_mem_buffer_file_write.cc',
'pdfium/pdfium_mem_buffer_file_write.h',
'pdfium/pdfium_page.cc',
'pdfium/pdfium_page.h',
'pdfium/pdfium_range.cc',
'pdfium/pdfium_range.h',
],
}],
['OS!="win"', {
'sources!': [
'pdf.rc',
],
}],
['OS=="mac"', {
'mac_bundle': 1,
'product_name': 'PDF',
'product_extension': 'plugin',
# Strip the shipping binary of symbols so "Foxit" doesn't appear in
# the binary. Symbols are stored in a separate .dSYM.
'variables': {
'mac_real_dsym': 1,
},
'sources+': [
'Info.plist'
],
}],
['OS=="win"', {
'defines': [
'COMPILE_CONTENT_STATICALLY',
],
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
}],
['OS=="linux"', {
'configurations': {
'Release_Base': {
#'cflags': [ '-fno-weak',], # get rid of symbols that strip doesn't remove.
# Don't do this for now since official builder will take care of it. That
# way symbols can still be uploaded to the crash server.
#'ldflags': [ '-s',], # strip local symbols from binary.
},
},
# Use a custom version script to prevent leaking the vendor name in
# visible symbols.
'ldflags': [
'-Wl,--version-script=<!(cd <(DEPTH) && pwd -P)/pdf/libpdf.map'
],
}],
],
},
{
'target_name': 'pdfium_test',
'type': 'executable',
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:base_i18n',
'../third_party/pdfium/pdfium.gyp:fpdfsdk',
],
'sources': [
'pdfium/pdfium_test.cc',
],
}
],
'conditions': [
# CrOS has a separate step to do this.
['OS=="linux" and chromeos==0',
{ 'targets': [
{
'target_name': 'pdf_linux_symbols',
'type': 'none',
'conditions': [
['linux_dump_symbols==1', {
'actions': [
{
'action_name': 'dump_symbols',
'inputs': [
'<(DEPTH)/build/linux/dump_app_syms',
'<(PRODUCT_DIR)/dump_syms',
'<(PRODUCT_DIR)/libpdf.so',
],
'outputs': [
'<(PRODUCT_DIR)/libpdf.so.breakpad.<(target_arch)',
],
'action': ['<(DEPTH)/build/linux/dump_app_syms',
'<(PRODUCT_DIR)/dump_syms',
'<(linux_strip_binary)',
'<(PRODUCT_DIR)/libpdf.so',
'<@(_outputs)'],
'message': 'Dumping breakpad symbols to <(_outputs)',
'process_outputs_as_sources': 1,
},
],
'dependencies': [
'pdf',
'../breakpad/breakpad.gyp:dump_syms',
],
}],
],
},
],
},], # OS=="linux" and chromeos==0
],
}

24
pdf/pdf.h Normal file

@ -0,0 +1,24 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDF_H_
#define PDF_PDF_H_
#include "ppapi/cpp/module.h"
namespace chrome_pdf {
class PDFModule : public pp::Module {
public:
PDFModule();
virtual ~PDFModule();
// pp::Module implementation.
virtual bool Init();
virtual pp::Instance* CreateInstance(PP_Instance instance);
};
} // namespace chrome_pdf
#endif // PDF_PDF_H_

104
pdf/pdf.rc Normal file

@ -0,0 +1,104 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "FileDescription", "Chrome PDF Viewer"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "pdf"
VALUE "LegalCopyright", "Copyright (C) 2010"
VALUE "MIMEType", "application/pdf"
VALUE "FileExtents", "pdf"
VALUE "FileOpenName", "Acrobat Portable Document Format"
VALUE "OriginalFilename", "pdf.dll"
VALUE "ProductName", "Chrome PDF Viewer"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

319
pdf/pdf_engine.h Normal file

@ -0,0 +1,319 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDF_ENGINE_H_
#define PDF_PDF_ENGINE_H_
#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "ppapi/c/dev/pp_cursor_type_dev.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/ppb_input_event.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/size.h"
#include "ppapi/cpp/url_loader.h"
namespace pp {
class InputEvent;
}
#define kBackgroundColorR 204
#define kBackgroundColorG 204
#define kBackgroundColorB 204
#define kBackgroundColorA 255
namespace chrome_pdf {
class Stream;
#if defined(OS_MACOSX)
const uint32 kDefaultKeyModifier = PP_INPUTEVENT_MODIFIER_METAKEY;
#else // !OS_MACOSX
const uint32 kDefaultKeyModifier = PP_INPUTEVENT_MODIFIER_CONTROLKEY;
#endif // OS_MACOSX
// Do one time initialization of the SDK. data is platform specific, on Windows
// it's the instance of the DLL and it's unused on other platforms.
bool InitializeSDK(void* data);
// Tells the SDK that we're shutting down.
void ShutdownSDK();
// This class encapsulates a PDF rendering engine.
class PDFEngine {
public:
enum DocumentPermission {
PERMISSION_COPY,
PERMISSION_COPY_ACCESSIBLE,
PERMISSION_PRINT_LOW_QUALITY,
PERMISSION_PRINT_HIGH_QUALITY,
};
// The interface that's provided to the rendering engine.
class Client {
public:
// Informs the client about the document's size in pixels.
virtual void DocumentSizeUpdated(const pp::Size& size) = 0;
// Informs the client that the given rect needs to be repainted.
virtual void Invalidate(const pp::Rect& rect) = 0;
// Informs the client to scroll the plugin area by the given offset.
virtual void Scroll(const pp::Point& point) = 0;
// Scroll the horizontal/vertical scrollbars to a given position.
virtual void ScrollToX(int position) = 0;
virtual void ScrollToY(int position) = 0;
// Scroll to the specified page.
virtual void ScrollToPage(int page) = 0;
// Navigate to the given url.
virtual void NavigateTo(const std::string& url, bool open_in_new_tab) = 0;
// Updates the cursor.
virtual void UpdateCursor(PP_CursorType_Dev cursor) = 0;
// Updates the tick marks in the vertical scrollbar.
virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks) = 0;
// Updates the number of find results for the current search term. If
// there are no matches 0 should be passed in. Only when the plugin has
// finished searching should it pass in the final count with final_result
// set to true.
virtual void NotifyNumberOfFindResultsChanged(int total,
bool final_result) = 0;
// Updates the index of the currently selected search item.
virtual void NotifySelectedFindResultChanged(int current_find_index) = 0;
// Prompts the user for a password to open this document. The callback is
// called when the password is retrieved.
virtual void GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback) = 0;
// Puts up an alert with the given message.
virtual void Alert(const std::string& message) = 0;
// Puts up a confirm with the given message, and returns true if the user
// presses OK, or false if they press cancel.
virtual bool Confirm(const std::string& message) = 0;
// Puts up a prompt with the given message and default answer and returns
// the answer.
virtual std::string Prompt(const std::string& question,
const std::string& default_answer) = 0;
// Returns the url of the pdf.
virtual std::string GetURL() = 0;
// Send an email.
virtual void Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body) = 0;
// Put up the print dialog.
virtual void Print() = 0;
// Submit the data using HTTP POST.
virtual void SubmitForm(const std::string& url,
const void* data,
int length) = 0;
// Pops up a file selection dialog and returns the result.
virtual std::string ShowFileSelectionDialog() = 0;
// Creates and returns new URL loader for partial document requests.
virtual pp::URLLoader CreateURLLoader() = 0;
// Calls the client's OnCallback() function in delay_in_ms with the given
// id.
virtual void ScheduleCallback(int id, int delay_in_ms) = 0;
// Searches the given string for "term" and returns the results. Unicode-
// aware.
struct SearchStringResult {
int start_index;
int length;
};
virtual void SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive,
std::vector<SearchStringResult>* results) = 0;
// Notifies the client that the engine has painted a page from the document.
virtual void DocumentPaintOccurred() = 0;
// Notifies the client that the document has finished loading.
virtual void DocumentLoadComplete(int page_count) = 0;
// Notifies the client that the document has failed to load.
virtual void DocumentLoadFailed() = 0;
virtual pp::Instance* GetPluginInstance() = 0;
// Notifies that an unsupported feature in the PDF was encountered.
virtual void DocumentHasUnsupportedFeature(const std::string& feature) = 0;
// Notifies the client about document load progress.
virtual void DocumentLoadProgress(uint32 available, uint32 doc_size) = 0;
// Notifies the client about focus changes for form text fields.
virtual void FormTextFieldFocusChange(bool in_focus) = 0;
// Returns true if the plugin has been opened within print preview.
virtual bool IsPrintPreview() = 0;
};
// Factory method to create an instance of the PDF Engine.
static PDFEngine* Create(Client* client);
virtual ~PDFEngine() {}
// Most of these functions are similar to the Pepper functions of the same
// name, so not repeating the description here unless it's different.
virtual bool New(const char* url) = 0;
virtual bool New(const char* url,
const char* headers) = 0;
virtual void PageOffsetUpdated(const pp::Point& page_offset) = 0;
virtual void PluginSizeUpdated(const pp::Size& size) = 0;
virtual void ScrolledToXPosition(int position) = 0;
virtual void ScrolledToYPosition(int position) = 0;
// Paint is called a series of times. Before these n calls are made, PrePaint
// is called once. After Paint is called n times, PostPaint is called once.
virtual void PrePaint() = 0;
virtual void Paint(const pp::Rect& rect,
pp::ImageData* image_data,
std::vector<pp::Rect>* ready,
std::vector<pp::Rect>* pending) = 0;
virtual void PostPaint() = 0;
virtual bool HandleDocumentLoad(const pp::URLLoader& loader) = 0;
virtual bool HandleEvent(const pp::InputEvent& event) = 0;
virtual uint32_t QuerySupportedPrintOutputFormats() = 0;
virtual void PrintBegin() = 0;
virtual pp::Resource PrintPages(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) = 0;
virtual void PrintEnd() = 0;
virtual void StartFind(const char* text, bool case_sensitive) = 0;
virtual bool SelectFindResult(bool forward) = 0;
virtual void StopFind() = 0;
virtual void ZoomUpdated(double new_zoom_level) = 0;
virtual void RotateClockwise() = 0;
virtual void RotateCounterclockwise() = 0;
virtual std::string GetSelectedText() = 0;
virtual std::string GetLinkAtPosition(const pp::Point& point) = 0;
virtual bool IsSelecting() = 0;
// Checks the permissions associated with this document.
virtual bool HasPermission(DocumentPermission permission) const = 0;
virtual void SelectAll() = 0;
// Gets the number of pages in the document.
virtual int GetNumberOfPages() = 0;
// Gets the 0-based page number of |destination|, or -1 if it does not exist.
virtual int GetNamedDestinationPage(const std::string& destination) = 0;
// Gets the index of the first visible page, or -1 if none are visible.
virtual int GetFirstVisiblePage() = 0;
// Gets the index of the most visible page, or -1 if none are visible.
virtual int GetMostVisiblePage() = 0;
// Gets the rectangle of the page including shadow.
virtual pp::Rect GetPageRect(int index) = 0;
// Gets the rectangle of the page excluding any additional areas.
virtual pp::Rect GetPageContentsRect(int index) = 0;
// Gets the offset of the vertical scrollbar from the top in document
// coordinates.
virtual int GetVerticalScrollbarYPosition() = 0;
// Paints page thumbnail to the ImageData.
virtual void PaintThumbnail(pp::ImageData* image_data, int index) = 0;
// Set color / grayscale rendering modes.
virtual void SetGrayscale(bool grayscale) = 0;
// Callback for timer that's set with ScheduleCallback().
virtual void OnCallback(int id) = 0;
// Gets the JSON representation of the PDF file
virtual std::string GetPageAsJSON(int index) = 0;
// Gets the PDF document's print scaling preference. True if the document can
// be scaled to fit.
virtual bool GetPrintScaling() = 0;
// Append blank pages to make a 1-page document to a |num_pages| document.
// Always retain the first page data.
virtual void AppendBlankPages(int num_pages) = 0;
// Append the first page of the document loaded with the |engine| to this
// document at page |index|.
virtual void AppendPage(PDFEngine* engine, int index) = 0;
// Allow client to query and reset scroll positions in document coordinates.
// Note that this is meant for cases where the device scale factor changes,
// and not for general scrolling - the engine will not repaint due to this.
virtual pp::Point GetScrollPosition() = 0;
virtual void SetScrollPosition(const pp::Point& position) = 0;
virtual bool IsProgressiveLoad() = 0;
};
// Interface for exports that wrap the PDF engine.
class PDFEngineExports {
public:
struct RenderingSettings {
RenderingSettings(int dpi_x,
int dpi_y,
const pp::Rect& bounds,
bool fit_to_bounds,
bool stretch_to_bounds,
bool keep_aspect_ratio,
bool center_in_bounds,
bool autorotate)
: dpi_x(dpi_x), dpi_y(dpi_y), bounds(bounds),
fit_to_bounds(fit_to_bounds), stretch_to_bounds(stretch_to_bounds),
keep_aspect_ratio(keep_aspect_ratio),
center_in_bounds(center_in_bounds), autorotate(autorotate) {
}
int dpi_x;
int dpi_y;
pp::Rect bounds;
bool fit_to_bounds;
bool stretch_to_bounds;
bool keep_aspect_ratio;
bool center_in_bounds;
bool autorotate;
};
PDFEngineExports() {}
virtual ~PDFEngineExports() {}
static PDFEngineExports* Create();
#if defined(OS_WIN)
// See the definition of RenderPDFPageToDC in pdf.cc for details.
virtual bool RenderPDFPageToDC(const void* pdf_buffer,
int buffer_size,
int page_number,
const RenderingSettings& settings,
HDC dc) = 0;
#endif // OS_WIN
// See the definition of RenderPDFPageToBitmap in pdf.cc for details.
virtual bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,
int page_number,
const RenderingSettings& settings,
void* bitmap_buffer) = 0;
virtual bool GetPDFDocInfo(const void* pdf_buffer,
int buffer_size,
int* page_count,
double* max_page_width) = 0;
};
} // namespace chrome_pdf
#endif // PDF_PDF_ENGINE_H_

@ -0,0 +1,207 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/basictypes.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_fwlevent.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_sysfontinfo.h"
#include "ui/events/keycodes/keyboard_codes.h"
#define COMPILE_ASSERT_MATCH(np_name, pdfium_name) \
COMPILE_ASSERT(int(np_name) == int(pdfium_name), mismatching_enums)
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_SHIFTKEY, FWL_EVENTFLAG_ShiftKey);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_CONTROLKEY,
FWL_EVENTFLAG_ControlKey);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_ALTKEY, FWL_EVENTFLAG_AltKey);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_METAKEY, FWL_EVENTFLAG_MetaKey);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_ISKEYPAD, FWL_EVENTFLAG_KeyPad);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT,
FWL_EVENTFLAG_AutoRepeat);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN,
FWL_EVENTFLAG_LeftButtonDown);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN,
FWL_EVENTFLAG_MiddleButtonDown);
COMPILE_ASSERT_MATCH(PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN,
FWL_EVENTFLAG_RightButtonDown);
COMPILE_ASSERT_MATCH(ui::VKEY_BACK, FWL_VKEY_Back);
COMPILE_ASSERT_MATCH(ui::VKEY_TAB, FWL_VKEY_Tab);
COMPILE_ASSERT_MATCH(ui::VKEY_CLEAR, FWL_VKEY_Clear);
COMPILE_ASSERT_MATCH(ui::VKEY_RETURN, FWL_VKEY_Return);
COMPILE_ASSERT_MATCH(ui::VKEY_SHIFT, FWL_VKEY_Shift);
COMPILE_ASSERT_MATCH(ui::VKEY_CONTROL, FWL_VKEY_Control);
COMPILE_ASSERT_MATCH(ui::VKEY_MENU, FWL_VKEY_Menu);
COMPILE_ASSERT_MATCH(ui::VKEY_PAUSE, FWL_VKEY_Pause);
COMPILE_ASSERT_MATCH(ui::VKEY_CAPITAL, FWL_VKEY_Capital);
COMPILE_ASSERT_MATCH(ui::VKEY_KANA, FWL_VKEY_Kana);
COMPILE_ASSERT_MATCH(ui::VKEY_HANGUL, FWL_VKEY_Hangul);
COMPILE_ASSERT_MATCH(ui::VKEY_JUNJA, FWL_VKEY_Junja);
COMPILE_ASSERT_MATCH(ui::VKEY_FINAL, FWL_VKEY_Final);
COMPILE_ASSERT_MATCH(ui::VKEY_HANJA, FWL_VKEY_Hanja);
COMPILE_ASSERT_MATCH(ui::VKEY_KANJI, FWL_VKEY_Kanji);
COMPILE_ASSERT_MATCH(ui::VKEY_ESCAPE, FWL_VKEY_Escape);
COMPILE_ASSERT_MATCH(ui::VKEY_CONVERT, FWL_VKEY_Convert);
COMPILE_ASSERT_MATCH(ui::VKEY_NONCONVERT, FWL_VKEY_NonConvert);
COMPILE_ASSERT_MATCH(ui::VKEY_ACCEPT, FWL_VKEY_Accept);
COMPILE_ASSERT_MATCH(ui::VKEY_MODECHANGE, FWL_VKEY_ModeChange);
COMPILE_ASSERT_MATCH(ui::VKEY_SPACE, FWL_VKEY_Space);
COMPILE_ASSERT_MATCH(ui::VKEY_PRIOR, FWL_VKEY_Prior);
COMPILE_ASSERT_MATCH(ui::VKEY_NEXT, FWL_VKEY_Next);
COMPILE_ASSERT_MATCH(ui::VKEY_END, FWL_VKEY_End);
COMPILE_ASSERT_MATCH(ui::VKEY_HOME, FWL_VKEY_Home);
COMPILE_ASSERT_MATCH(ui::VKEY_LEFT, FWL_VKEY_Left);
COMPILE_ASSERT_MATCH(ui::VKEY_UP, FWL_VKEY_Up);
COMPILE_ASSERT_MATCH(ui::VKEY_RIGHT, FWL_VKEY_Right);
COMPILE_ASSERT_MATCH(ui::VKEY_DOWN, FWL_VKEY_Down);
COMPILE_ASSERT_MATCH(ui::VKEY_SELECT, FWL_VKEY_Select);
COMPILE_ASSERT_MATCH(ui::VKEY_PRINT, FWL_VKEY_Print);
COMPILE_ASSERT_MATCH(ui::VKEY_EXECUTE, FWL_VKEY_Execute);
COMPILE_ASSERT_MATCH(ui::VKEY_SNAPSHOT, FWL_VKEY_Snapshot);
COMPILE_ASSERT_MATCH(ui::VKEY_INSERT, FWL_VKEY_Insert);
COMPILE_ASSERT_MATCH(ui::VKEY_DELETE, FWL_VKEY_Delete);
COMPILE_ASSERT_MATCH(ui::VKEY_HELP, FWL_VKEY_Help);
COMPILE_ASSERT_MATCH(ui::VKEY_0, FWL_VKEY_0);
COMPILE_ASSERT_MATCH(ui::VKEY_1, FWL_VKEY_1);
COMPILE_ASSERT_MATCH(ui::VKEY_2, FWL_VKEY_2);
COMPILE_ASSERT_MATCH(ui::VKEY_3, FWL_VKEY_3);
COMPILE_ASSERT_MATCH(ui::VKEY_4, FWL_VKEY_4);
COMPILE_ASSERT_MATCH(ui::VKEY_5, FWL_VKEY_5);
COMPILE_ASSERT_MATCH(ui::VKEY_6, FWL_VKEY_6);
COMPILE_ASSERT_MATCH(ui::VKEY_7, FWL_VKEY_7);
COMPILE_ASSERT_MATCH(ui::VKEY_8, FWL_VKEY_8);
COMPILE_ASSERT_MATCH(ui::VKEY_9, FWL_VKEY_9);
COMPILE_ASSERT_MATCH(ui::VKEY_A, FWL_VKEY_A);
COMPILE_ASSERT_MATCH(ui::VKEY_B, FWL_VKEY_B);
COMPILE_ASSERT_MATCH(ui::VKEY_C, FWL_VKEY_C);
COMPILE_ASSERT_MATCH(ui::VKEY_D, FWL_VKEY_D);
COMPILE_ASSERT_MATCH(ui::VKEY_E, FWL_VKEY_E);
COMPILE_ASSERT_MATCH(ui::VKEY_F, FWL_VKEY_F);
COMPILE_ASSERT_MATCH(ui::VKEY_G, FWL_VKEY_G);
COMPILE_ASSERT_MATCH(ui::VKEY_H, FWL_VKEY_H);
COMPILE_ASSERT_MATCH(ui::VKEY_I, FWL_VKEY_I);
COMPILE_ASSERT_MATCH(ui::VKEY_J, FWL_VKEY_J);
COMPILE_ASSERT_MATCH(ui::VKEY_K, FWL_VKEY_K);
COMPILE_ASSERT_MATCH(ui::VKEY_L, FWL_VKEY_L);
COMPILE_ASSERT_MATCH(ui::VKEY_M, FWL_VKEY_M);
COMPILE_ASSERT_MATCH(ui::VKEY_N, FWL_VKEY_N);
COMPILE_ASSERT_MATCH(ui::VKEY_O, FWL_VKEY_O);
COMPILE_ASSERT_MATCH(ui::VKEY_P, FWL_VKEY_P);
COMPILE_ASSERT_MATCH(ui::VKEY_Q, FWL_VKEY_Q);
COMPILE_ASSERT_MATCH(ui::VKEY_R, FWL_VKEY_R);
COMPILE_ASSERT_MATCH(ui::VKEY_S, FWL_VKEY_S);
COMPILE_ASSERT_MATCH(ui::VKEY_T, FWL_VKEY_T);
COMPILE_ASSERT_MATCH(ui::VKEY_U, FWL_VKEY_U);
COMPILE_ASSERT_MATCH(ui::VKEY_V, FWL_VKEY_V);
COMPILE_ASSERT_MATCH(ui::VKEY_W, FWL_VKEY_W);
COMPILE_ASSERT_MATCH(ui::VKEY_X, FWL_VKEY_X);
COMPILE_ASSERT_MATCH(ui::VKEY_Y, FWL_VKEY_Y);
COMPILE_ASSERT_MATCH(ui::VKEY_Z, FWL_VKEY_Z);
COMPILE_ASSERT_MATCH(ui::VKEY_LWIN, FWL_VKEY_LWin);
COMPILE_ASSERT_MATCH(ui::VKEY_COMMAND, FWL_VKEY_Command);
COMPILE_ASSERT_MATCH(ui::VKEY_RWIN, FWL_VKEY_RWin);
COMPILE_ASSERT_MATCH(ui::VKEY_APPS, FWL_VKEY_Apps);
COMPILE_ASSERT_MATCH(ui::VKEY_SLEEP, FWL_VKEY_Sleep);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD0, FWL_VKEY_NumPad0);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD1, FWL_VKEY_NumPad1);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD2, FWL_VKEY_NumPad2);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD3, FWL_VKEY_NumPad3);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD4, FWL_VKEY_NumPad4);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD5, FWL_VKEY_NumPad5);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD6, FWL_VKEY_NumPad6);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD7, FWL_VKEY_NumPad7);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD8, FWL_VKEY_NumPad8);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMPAD9, FWL_VKEY_NumPad9);
COMPILE_ASSERT_MATCH(ui::VKEY_MULTIPLY, FWL_VKEY_Multiply);
COMPILE_ASSERT_MATCH(ui::VKEY_ADD, FWL_VKEY_Add);
COMPILE_ASSERT_MATCH(ui::VKEY_SEPARATOR, FWL_VKEY_Separator);
COMPILE_ASSERT_MATCH(ui::VKEY_SUBTRACT, FWL_VKEY_Subtract);
COMPILE_ASSERT_MATCH(ui::VKEY_DECIMAL, FWL_VKEY_Decimal);
COMPILE_ASSERT_MATCH(ui::VKEY_DIVIDE, FWL_VKEY_Divide);
COMPILE_ASSERT_MATCH(ui::VKEY_F1, FWL_VKEY_F1);
COMPILE_ASSERT_MATCH(ui::VKEY_F2, FWL_VKEY_F2);
COMPILE_ASSERT_MATCH(ui::VKEY_F3, FWL_VKEY_F3);
COMPILE_ASSERT_MATCH(ui::VKEY_F4, FWL_VKEY_F4);
COMPILE_ASSERT_MATCH(ui::VKEY_F5, FWL_VKEY_F5);
COMPILE_ASSERT_MATCH(ui::VKEY_F6, FWL_VKEY_F6);
COMPILE_ASSERT_MATCH(ui::VKEY_F7, FWL_VKEY_F7);
COMPILE_ASSERT_MATCH(ui::VKEY_F8, FWL_VKEY_F8);
COMPILE_ASSERT_MATCH(ui::VKEY_F9, FWL_VKEY_F9);
COMPILE_ASSERT_MATCH(ui::VKEY_F10, FWL_VKEY_F10);
COMPILE_ASSERT_MATCH(ui::VKEY_F11, FWL_VKEY_F11);
COMPILE_ASSERT_MATCH(ui::VKEY_F12, FWL_VKEY_F12);
COMPILE_ASSERT_MATCH(ui::VKEY_F13, FWL_VKEY_F13);
COMPILE_ASSERT_MATCH(ui::VKEY_F14, FWL_VKEY_F14);
COMPILE_ASSERT_MATCH(ui::VKEY_F15, FWL_VKEY_F15);
COMPILE_ASSERT_MATCH(ui::VKEY_F16, FWL_VKEY_F16);
COMPILE_ASSERT_MATCH(ui::VKEY_F17, FWL_VKEY_F17);
COMPILE_ASSERT_MATCH(ui::VKEY_F18, FWL_VKEY_F18);
COMPILE_ASSERT_MATCH(ui::VKEY_F19, FWL_VKEY_F19);
COMPILE_ASSERT_MATCH(ui::VKEY_F20, FWL_VKEY_F20);
COMPILE_ASSERT_MATCH(ui::VKEY_F21, FWL_VKEY_F21);
COMPILE_ASSERT_MATCH(ui::VKEY_F22, FWL_VKEY_F22);
COMPILE_ASSERT_MATCH(ui::VKEY_F23, FWL_VKEY_F23);
COMPILE_ASSERT_MATCH(ui::VKEY_F24, FWL_VKEY_F24);
COMPILE_ASSERT_MATCH(ui::VKEY_NUMLOCK, FWL_VKEY_NunLock);
COMPILE_ASSERT_MATCH(ui::VKEY_SCROLL, FWL_VKEY_Scroll);
COMPILE_ASSERT_MATCH(ui::VKEY_LSHIFT, FWL_VKEY_LShift);
COMPILE_ASSERT_MATCH(ui::VKEY_RSHIFT, FWL_VKEY_RShift);
COMPILE_ASSERT_MATCH(ui::VKEY_LCONTROL, FWL_VKEY_LControl);
COMPILE_ASSERT_MATCH(ui::VKEY_RCONTROL, FWL_VKEY_RControl);
COMPILE_ASSERT_MATCH(ui::VKEY_LMENU, FWL_VKEY_LMenu);
COMPILE_ASSERT_MATCH(ui::VKEY_RMENU, FWL_VKEY_RMenu);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_BACK, FWL_VKEY_BROWSER_Back);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_FORWARD, FWL_VKEY_BROWSER_Forward);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_REFRESH, FWL_VKEY_BROWSER_Refresh);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_STOP, FWL_VKEY_BROWSER_Stop);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_SEARCH, FWL_VKEY_BROWSER_Search);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_FAVORITES, FWL_VKEY_BROWSER_Favorites);
COMPILE_ASSERT_MATCH(ui::VKEY_BROWSER_HOME, FWL_VKEY_BROWSER_Home);
COMPILE_ASSERT_MATCH(ui::VKEY_VOLUME_MUTE, FWL_VKEY_VOLUME_Mute);
COMPILE_ASSERT_MATCH(ui::VKEY_VOLUME_DOWN, FWL_VKEY_VOLUME_Down);
COMPILE_ASSERT_MATCH(ui::VKEY_VOLUME_UP, FWL_VKEY_VOLUME_Up);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_NEXT_TRACK, FWL_VKEY_MEDIA_NEXT_Track);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_PREV_TRACK, FWL_VKEY_MEDIA_PREV_Track);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_STOP, FWL_VKEY_MEDIA_Stop);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_PLAY_PAUSE, FWL_VKEY_MEDIA_PLAY_Pause);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_LAUNCH_MAIL, FWL_VKEY_MEDIA_LAUNCH_Mail);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_LAUNCH_MEDIA_SELECT,
FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_LAUNCH_APP1, FWL_VKEY_MEDIA_LAUNCH_APP1);
COMPILE_ASSERT_MATCH(ui::VKEY_MEDIA_LAUNCH_APP2, FWL_VKEY_MEDIA_LAUNCH_APP2);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_1, FWL_VKEY_OEM_1);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_PLUS, FWL_VKEY_OEM_Plus);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_COMMA, FWL_VKEY_OEM_Comma);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_MINUS, FWL_VKEY_OEM_Minus);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_PERIOD, FWL_VKEY_OEM_Period);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_2, FWL_VKEY_OEM_2);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_3, FWL_VKEY_OEM_3);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_4, FWL_VKEY_OEM_4);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_5, FWL_VKEY_OEM_5);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_6, FWL_VKEY_OEM_6);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_7, FWL_VKEY_OEM_7);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_8, FWL_VKEY_OEM_8);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_102, FWL_VKEY_OEM_102);
COMPILE_ASSERT_MATCH(ui::VKEY_PROCESSKEY, FWL_VKEY_ProcessKey);
COMPILE_ASSERT_MATCH(ui::VKEY_PACKET, FWL_VKEY_Packet);
COMPILE_ASSERT_MATCH(ui::VKEY_ATTN, FWL_VKEY_Attn);
COMPILE_ASSERT_MATCH(ui::VKEY_CRSEL, FWL_VKEY_Crsel);
COMPILE_ASSERT_MATCH(ui::VKEY_EXSEL, FWL_VKEY_Exsel);
COMPILE_ASSERT_MATCH(ui::VKEY_EREOF, FWL_VKEY_Ereof);
COMPILE_ASSERT_MATCH(ui::VKEY_PLAY, FWL_VKEY_Play);
COMPILE_ASSERT_MATCH(ui::VKEY_ZOOM, FWL_VKEY_Zoom);
COMPILE_ASSERT_MATCH(ui::VKEY_NONAME, FWL_VKEY_NoName);
COMPILE_ASSERT_MATCH(ui::VKEY_PA1, FWL_VKEY_PA1);
COMPILE_ASSERT_MATCH(ui::VKEY_OEM_CLEAR, FWL_VKEY_OEM_Clear);
COMPILE_ASSERT_MATCH(ui::VKEY_UNKNOWN, FWL_VKEY_Unknown);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_ANSI, FXFONT_ANSI_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_DEFAULT, FXFONT_DEFAULT_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_SYMBOL, FXFONT_SYMBOL_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_SHIFTJIS, FXFONT_SHIFTJIS_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_HANGUL, FXFONT_HANGEUL_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_GB2312, FXFONT_GB2312_CHARSET);
COMPILE_ASSERT_MATCH(PP_PRIVATEFONTCHARSET_CHINESEBIG5,
FXFONT_CHINESEBIG5_CHARSET);

3389
pdf/pdfium/pdfium_engine.cc Normal file

File diff suppressed because it is too large Load Diff

621
pdf/pdfium/pdfium_engine.h Normal file

@ -0,0 +1,621 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_ENGINE_H_
#define PDF_PDFIUM_PDFIUM_ENGINE_H_
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "pdf/document_loader.h"
#include "pdf/pdf_engine.h"
#include "pdf/pdfium/pdfium_page.h"
#include "pdf/pdfium/pdfium_range.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/dev/buffer_dev.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/point.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_dataavail.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_progressive.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfformfill.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfview.h"
namespace pp {
class KeyboardInputEvent;
class MouseInputEvent;
}
namespace chrome_pdf {
class ShadowMatrix;
class PDFiumEngine : public PDFEngine,
public DocumentLoader::Client,
public FPDF_FORMFILLINFO,
public IPDF_JSPLATFORM,
public IFSDK_PAUSE {
public:
explicit PDFiumEngine(PDFEngine::Client* client);
virtual ~PDFiumEngine();
// PDFEngine implementation.
virtual bool New(const char* url);
virtual bool New(const char* url,
const char* headers);
virtual void PageOffsetUpdated(const pp::Point& page_offset);
virtual void PluginSizeUpdated(const pp::Size& size);
virtual void ScrolledToXPosition(int position);
virtual void ScrolledToYPosition(int position);
virtual void PrePaint();
virtual void Paint(const pp::Rect& rect,
pp::ImageData* image_data,
std::vector<pp::Rect>* ready,
std::vector<pp::Rect>* pending);
virtual void PostPaint();
virtual bool HandleDocumentLoad(const pp::URLLoader& loader);
virtual bool HandleEvent(const pp::InputEvent& event);
virtual uint32_t QuerySupportedPrintOutputFormats();
virtual void PrintBegin();
virtual pp::Resource PrintPages(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
virtual void PrintEnd();
virtual void StartFind(const char* text, bool case_sensitive);
virtual bool SelectFindResult(bool forward);
virtual void StopFind();
virtual void ZoomUpdated(double new_zoom_level);
virtual void RotateClockwise();
virtual void RotateCounterclockwise();
virtual std::string GetSelectedText();
virtual std::string GetLinkAtPosition(const pp::Point& point);
virtual bool IsSelecting();
virtual bool HasPermission(DocumentPermission permission) const;
virtual void SelectAll();
virtual int GetNumberOfPages();
virtual int GetNamedDestinationPage(const std::string& destination);
virtual int GetFirstVisiblePage();
virtual int GetMostVisiblePage();
virtual pp::Rect GetPageRect(int index);
virtual pp::Rect GetPageContentsRect(int index);
virtual int GetVerticalScrollbarYPosition() { return position_.y(); }
virtual void PaintThumbnail(pp::ImageData* image_data, int index);
virtual void SetGrayscale(bool grayscale);
virtual void OnCallback(int id);
virtual std::string GetPageAsJSON(int index);
virtual bool GetPrintScaling();
virtual void AppendBlankPages(int num_pages);
virtual void AppendPage(PDFEngine* engine, int index);
virtual pp::Point GetScrollPosition();
virtual void SetScrollPosition(const pp::Point& position);
virtual bool IsProgressiveLoad();
// DocumentLoader::Client implementation.
virtual pp::Instance* GetPluginInstance();
virtual pp::URLLoader CreateURLLoader();
virtual void OnPartialDocumentLoaded();
virtual void OnPendingRequestComplete();
virtual void OnNewDataAvailable();
virtual void OnDocumentComplete();
void UnsupportedFeature(int type);
std::string current_find_text() const { return current_find_text_; }
FPDF_DOCUMENT doc() { return doc_; }
FPDF_FORMHANDLE form() { return form_; }
private:
// This helper class is used to detect the difference in selection between
// construction and destruction. At destruction, it invalidates all the
// parts that are newly selected, along with all the parts that used to be
// selected but are not anymore.
class SelectionChangeInvalidator {
public:
explicit SelectionChangeInvalidator(PDFiumEngine* engine);
~SelectionChangeInvalidator();
private:
// Sets the given container to the all the currently visible selection
// rectangles, in screen coordinates.
void GetVisibleSelectionsScreenRects(std::vector<pp::Rect>* rects);
PDFiumEngine* engine_;
// Screen rectangles that were selected on construction.
std::vector<pp::Rect> old_selections_;
// The origin at the time this object was constructed.
pp::Point previous_origin_;
};
friend class SelectionChangeInvalidator;
struct FileAvail : public FX_FILEAVAIL {
DocumentLoader* loader;
};
struct DownloadHints : public FX_DOWNLOADHINTS {
DocumentLoader* loader;
};
// PDFium interface to get block of data.
static int GetBlock(void* param, unsigned long position,
unsigned char* buffer, unsigned long size);
// PDFium interface to check is block of data is available.
static bool IsDataAvail(FX_FILEAVAIL* param,
size_t offset, size_t size);
// PDFium interface to request download of the block of data.
static void AddSegment(FX_DOWNLOADHINTS* param,
size_t offset, size_t size);
// We finished getting the pdf file, so load it. This will complete
// asynchronously (due to password fetching) and may be run multiple times.
void LoadDocument();
// Try loading the document. Returns true if the document is successfully
// loaded or is already loaded otherwise it will return false. If
// |with_password| is set to true, the document will be loaded with
// |password|. If the document could not be loaded and needs a password,
// |needs_password| will be set to true.
bool TryLoadingDoc(bool with_password,
const std::string& password,
bool* needs_password);
// Ask the user for the document password and then continue loading the
// document.
void GetPasswordAndLoad();
// Called when the password has been retrieved.
void OnGetPasswordComplete(int32_t result,
const pp::Var& password);
// Continues loading the document when the password has been retrieved, or if
// there is no password.
void ContinueLoadingDocument(bool has_password,
const std::string& password);
// Finish loading the document and notify the client that the document has
// been loaded. This should only be run after |doc_| has been loaded and the
// document is fully downloaded. If this has been run once, it will result in
// a no-op.
void FinishLoadingDocument();
// Loads information about the pages in the document and calculate the
// document size.
void LoadPageInfo(bool reload);
// Calculate which pages should be displayed right now.
void CalculateVisiblePages();
// Returns true iff the given page index is visible. CalculateVisiblePages
// must have been called first.
bool IsPageVisible(int index) const;
// Checks if a page is now available, and if so marks it as such and returns
// true. Otherwise, it will return false and will add the index to the given
// array if it's not already there.
bool CheckPageAvailable(int index, std::vector<int>* pending);
// Helper function to get a given page's size in pixels. This is not part of
// PDFiumPage because we might not have that structure when we need this.
pp::Size GetPageSize(int index);
void UpdateTickMarks();
// Called to continue searching so we don't block the main thread.
void ContinueFind(int32_t result);
// Inserts a find result into find_results_, which is sorted.
void AddFindResult(const PDFiumRange& result);
// Search a page using PDFium's methods. Doesn't work with unicode. This
// function is just kept arount in case PDFium code is fixed.
void SearchUsingPDFium(const base::string16& term,
bool case_sensitive,
bool first_search,
int character_to_start_searching_from,
int current_page);
// Search a page ourself using ICU.
void SearchUsingICU(const base::string16& term,
bool case_sensitive,
bool first_search,
int character_to_start_searching_from,
int current_page);
// Input event handlers.
bool OnMouseDown(const pp::MouseInputEvent& event);
bool OnMouseUp(const pp::MouseInputEvent& event);
bool OnMouseMove(const pp::MouseInputEvent& event);
bool OnKeyDown(const pp::KeyboardInputEvent& event);
bool OnKeyUp(const pp::KeyboardInputEvent& event);
bool OnChar(const pp::KeyboardInputEvent& event);
pp::Buffer_Dev PrintPagesAsRasterPDF(
const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
pp::Buffer_Dev PrintPagesAsPDF(const PP_PrintPageNumberRange_Dev* page_ranges,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
pp::Buffer_Dev GetFlattenedPrintData(const FPDF_DOCUMENT& doc);
void FitContentsToPrintableAreaIfRequired(
const FPDF_DOCUMENT& doc,
const PP_PrintSettings_Dev& print_settings);
void SaveSelectedFormForPrint();
// Given a mouse event, returns which page and character location it's closest
// to.
PDFiumPage::Area GetCharIndex(const pp::MouseInputEvent& event,
int* page_index,
int* char_index,
PDFiumPage::LinkTarget* target);
PDFiumPage::Area GetCharIndex(const pp::Point& point,
int* page_index,
int* char_index,
PDFiumPage::LinkTarget* target);
void OnSingleClick(int page_index, int char_index);
void OnMultipleClick(int click_count, int page_index, int char_index);
// Starts a progressive paint operation given a rectangle in screen
// coordinates. Returns the index in progressive_rects_.
int StartPaint(int page_index, const pp::Rect& dirty);
// Continues a paint operation that was started earlier. Returns true if the
// paint is done, or false if it needs to be continued.
bool ContinuePaint(int progressive_index, pp::ImageData* image_data);
// Called once PDFium is finished rendering a page so that we draw our
// borders, highlighting etc.
void FinishPaint(int progressive_index, pp::ImageData* image_data);
// Stops any paints that are in progress.
void CancelPaints();
// Invalidates all pages. Use this when some global parameter, such as page
// orientation, has changed.
void InvalidateAllPages();
// If the page is narrower than the document size, paint the extra space
// with the page background.
void FillPageSides(int progressive_index);
void PaintPageShadow(int progressive_index, pp::ImageData* image_data);
// Highlight visible find results and selections.
void DrawSelections(int progressive_index, pp::ImageData* image_data);
// Paints an page that hasn't finished downloading.
void PaintUnavailablePage(int page_index,
const pp::Rect& dirty,
pp::ImageData* image_data);
// Given a page index, returns the corresponding index in progressive_rects_,
// or -1 if it doesn't exist.
int GetProgressiveIndex(int page_index) const;
// Creates a FPDF_BITMAP from a rectangle in screen coordinates.
FPDF_BITMAP CreateBitmap(const pp::Rect& rect,
pp::ImageData* image_data) const;
// Given a rectangle in screen coordinates, returns the coordinates in the
// units that PDFium rendering functions expect.
void GetPDFiumRect(int page_index, const pp::Rect& rect, int* start_x,
int* start_y, int* size_x, int* size_y) const;
// Returns the rendering flags to pass to PDFium.
int GetRenderingFlags() const;
// Returns the currently visible rectangle in document coordinates.
pp::Rect GetVisibleRect() const;
// Returns a page's rect in screen coordinates, as well as its surrounding
// border areas and bottom separator.
pp::Rect GetPageScreenRect(int page_index) const;
// Given a rectangle in document coordinates, returns the rectange into screen
// coordinates (i.e. 0,0 is top left corner of plugin area). If it's not
// visible, an empty rectangle is returned.
pp::Rect GetScreenRect(const pp::Rect& rect) const;
// Highlights the given rectangle.
void Highlight(void* buffer,
int stride,
const pp::Rect& rect,
std::vector<pp::Rect>* highlighted_rects);
// Helper function to convert a device to page coordinates. If the page is
// not yet loaded, page_x and page_y will be set to 0.
void DeviceToPage(int page_index,
float device_x,
float device_y,
double* page_x,
double* page_y);
// Helper function to get the index of a given FPDF_PAGE. Returns -1 if not
// found.
int GetVisiblePageIndex(FPDF_PAGE page);
// Helper function to change the current page, running page open/close
// triggers as necessary.
void SetCurrentPage(int index);
// Transform |page| contents to fit in the selected printer paper size.
void TransformPDFPageForPrinting(FPDF_PAGE page,
const PP_PrintSettings_Dev& print_settings);
void DrawPageShadow(const pp::Rect& page_rect,
const pp::Rect& shadow_rect,
const pp::Rect& clip_rect,
pp::ImageData* image_data);
void GetRegion(const pp::Point& location,
pp::ImageData* image_data,
void** region,
int* stride) const;
// Called when the selection changes.
void OnSelectionChanged();
// FPDF_FORMFILLINFO callbacks.
static void Form_Invalidate(FPDF_FORMFILLINFO* param,
FPDF_PAGE page,
double left,
double top,
double right,
double bottom);
static void Form_OutputSelectedRect(FPDF_FORMFILLINFO* param,
FPDF_PAGE page,
double left,
double top,
double right,
double bottom);
static void Form_SetCursor(FPDF_FORMFILLINFO* param, int cursor_type);
static int Form_SetTimer(FPDF_FORMFILLINFO* param,
int elapse,
TimerCallback timer_func);
static void Form_KillTimer(FPDF_FORMFILLINFO* param, int timer_id);
static FPDF_SYSTEMTIME Form_GetLocalTime(FPDF_FORMFILLINFO* param);
static void Form_OnChange(FPDF_FORMFILLINFO* param);
static FPDF_PAGE Form_GetPage(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document,
int page_index);
static FPDF_PAGE Form_GetCurrentPage(FPDF_FORMFILLINFO* param,
FPDF_DOCUMENT document);
static int Form_GetRotation(FPDF_FORMFILLINFO* param, FPDF_PAGE page);
static void Form_ExecuteNamedAction(FPDF_FORMFILLINFO* param,
FPDF_BYTESTRING named_action);
static void Form_SetTextFieldFocus(FPDF_FORMFILLINFO* param,
FPDF_WIDESTRING value,
FPDF_DWORD valueLen,
FPDF_BOOL is_focus);
static void Form_DoURIAction(FPDF_FORMFILLINFO* param, FPDF_BYTESTRING uri);
static void Form_DoGoToAction(FPDF_FORMFILLINFO* param,
int page_index,
int zoom_mode,
float* position_array,
int size_of_array);
// IPDF_JSPLATFORM callbacks.
static int Form_Alert(IPDF_JSPLATFORM* param,
FPDF_WIDESTRING message,
FPDF_WIDESTRING title,
int type,
int icon);
static void Form_Beep(IPDF_JSPLATFORM* param, int type);
static int Form_Response(IPDF_JSPLATFORM* param,
FPDF_WIDESTRING question,
FPDF_WIDESTRING title,
FPDF_WIDESTRING default_response,
FPDF_WIDESTRING label,
FPDF_BOOL password,
void* response,
int length);
static int Form_GetFilePath(IPDF_JSPLATFORM* param,
void* file_path,
int length);
static void Form_Mail(IPDF_JSPLATFORM* param,
void* mail_data,
int length,
FPDF_BOOL ui,
FPDF_WIDESTRING to,
FPDF_WIDESTRING subject,
FPDF_WIDESTRING cc,
FPDF_WIDESTRING bcc,
FPDF_WIDESTRING message);
static void Form_Print(IPDF_JSPLATFORM* param,
FPDF_BOOL ui,
int start,
int end,
FPDF_BOOL silent,
FPDF_BOOL shrink_to_fit,
FPDF_BOOL print_as_image,
FPDF_BOOL reverse,
FPDF_BOOL annotations);
static void Form_SubmitForm(IPDF_JSPLATFORM* param,
void* form_data,
int length,
FPDF_WIDESTRING url);
static void Form_GotoPage(IPDF_JSPLATFORM* param, int page_number);
static int Form_Browse(IPDF_JSPLATFORM* param, void* file_path, int length);
// IFSDK_PAUSE callbacks
static FPDF_BOOL Pause_NeedToPauseNow(IFSDK_PAUSE* param);
PDFEngine::Client* client_;
pp::Size document_size_; // Size of document in pixels.
// The scroll position in screen coordinates.
pp::Point position_;
// The offset of the page into the viewport.
pp::Point page_offset_;
// The plugin size in screen coordinates.
pp::Size plugin_size_;
double current_zoom_;
unsigned int current_rotation_;
DocumentLoader doc_loader_; // Main document's loader.
std::string url_;
std::string headers_;
pp::CompletionCallbackFactory<PDFiumEngine> find_factory_;
pp::CompletionCallbackFactory<PDFiumEngine> password_factory_;
int32_t password_tries_remaining_;
// The current text used for searching.
std::string current_find_text_;
// The PDFium wrapper object for the document.
FPDF_DOCUMENT doc_;
// The PDFium wrapper for form data. Used even if there are no form controls
// on the page.
FPDF_FORMHANDLE form_;
// The page(s) of the document. Store a vector of pointers so that when the
// vector is resized we don't close the pages that are used in pending
// paints.
std::vector<PDFiumPage*> pages_;
// The indexes of the pages currently visible.
std::vector<int> visible_pages_;
// The indexes of the pages pending download.
std::vector<int> pending_pages_;
// During handling of input events we don't want to unload any pages in
// callbacks to us from PDFium, since the current page can change while PDFium
// code still has a pointer to it.
bool defer_page_unload_;
std::vector<int> deferred_page_unloads_;
// Used for selection. There could be more than one range if selection spans
// more than one page.
std::vector<PDFiumRange> selection_;
// True if we're in the middle of selection.
bool selecting_;
// Used for searching.
typedef std::vector<PDFiumRange> FindResults;
FindResults find_results_;
// Which page to search next.
int next_page_to_search_;
// Where to stop searching.
int last_page_to_search_;
int last_character_index_to_search_; // -1 if search until end of page.
// Which result the user has currently selected.
int current_find_index_;
// Permissions bitfield.
unsigned long permissions_;
// Interface structure to provide access to document stream.
FPDF_FILEACCESS file_access_;
// Interface structure to check data availability in the document stream.
FileAvail file_availability_;
// Interface structure to request data chunks from the document stream.
DownloadHints download_hints_;
// Pointer to the document availability interface.
FPDF_AVAIL fpdf_availability_;
pp::Size default_page_size_;
// Used to manage timers that form fill API needs. The pair holds the timer
// period, in ms, and the callback function.
std::map<int, std::pair<int, TimerCallback> > timers_;
int next_timer_id_;
// Holds the page index of the last page that the mouse clicked on.
int last_page_mouse_down_;
// Holds the page index of the first visible page; refreshed by calling
// CalculateVisiblePages()
int first_visible_page_;
// Holds the page index of the most visible page; refreshed by calling
// CalculateVisiblePages()
int most_visible_page_;
// Set to true after FORM_DoDocumentJSAction/FORM_DoDocumentOpenAction have
// been called. Only after that can we call FORM_DoPageAAction.
bool called_do_document_action_;
// Records parts of form fields that need to be highlighted at next paint, in
// screen coordinates.
std::vector<pp::Rect> form_highlights_;
// Whether to render in grayscale or in color.
bool render_grayscale_;
// The link currently under the cursor.
std::string link_under_cursor_;
// Pending progressive paints.
struct ProgressivePaint {
pp::Rect rect; // In screen coordinates.
FPDF_BITMAP bitmap;
int page_index;
// Temporary used to figure out if in a series of Paint() calls whether this
// pending paint was updated or not.
int painted_;
};
std::vector<ProgressivePaint> progressive_paints_;
// Keeps track of when we started the last progressive paint, so that in our
// callback we can determine if we need to pause.
base::Time last_progressive_start_time_;
// The timeout to use for the current progressive paint.
int progressive_paint_timeout_;
// Shadow matrix for generating the page shadow bitmap.
scoped_ptr<ShadowMatrix> page_shadow_;
// Set to true if the user is being prompted for their password. Will be set
// to false after the user finishes getting their password.
bool getting_password_;
};
// Create a local variable of this when calling PDFium functions which can call
// our global callback when an unsupported feature is reached.
class ScopedUnsupportedFeature {
public:
explicit ScopedUnsupportedFeature(PDFiumEngine* engine);
~ScopedUnsupportedFeature();
private:
PDFiumEngine* engine_;
PDFiumEngine* old_engine_;
};
class PDFiumEngineExports : public PDFEngineExports {
public:
PDFiumEngineExports() {}
#if defined(OS_WIN)
// See the definition of RenderPDFPageToDC in pdf.cc for details.
virtual bool RenderPDFPageToDC(const void* pdf_buffer,
int buffer_size,
int page_number,
const RenderingSettings& settings,
HDC dc);
#endif // OS_WIN
virtual bool RenderPDFPageToBitmap(const void* pdf_buffer,
int pdf_buffer_size,
int page_number,
const RenderingSettings& settings,
void* bitmap_buffer);
virtual bool GetPDFDocInfo(const void* pdf_buffer,
int buffer_size,
int* page_count,
double* max_page_width);
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_ENGINE_H_

@ -0,0 +1,34 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdfium/pdfium_mem_buffer_file_read.h"
#include <string.h>
namespace chrome_pdf {
PDFiumMemBufferFileRead::PDFiumMemBufferFileRead(const void* data,
size_t size) {
m_FileLen = size;
m_Param = this;
m_GetBlock = &GetBlock;
data_ = reinterpret_cast<const unsigned char*>(data);
}
PDFiumMemBufferFileRead::~PDFiumMemBufferFileRead() {
}
int PDFiumMemBufferFileRead::GetBlock(void* param,
unsigned long position,
unsigned char* buf,
unsigned long size) {
const PDFiumMemBufferFileRead* data =
reinterpret_cast<const PDFiumMemBufferFileRead*>(param);
if (!data || position + size > data->m_FileLen)
return 0;
memcpy(buf, data->data_ + position, size);
return 1;
}
} // namespace chrome_pdf

@ -0,0 +1,30 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_READ_H_
#define PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_READ_H_
#include <stdlib.h>
#include "third_party/pdfium/fpdfsdk/include/fpdfview.h"
namespace chrome_pdf {
// Implementation of FPDF_FILEACCESS from a memory buffer.
class PDFiumMemBufferFileRead : public FPDF_FILEACCESS {
public:
PDFiumMemBufferFileRead(const void* data, size_t size);
~PDFiumMemBufferFileRead();
private:
static int GetBlock(void* param,
unsigned long position,
unsigned char* buf,
unsigned long size);
const unsigned char* data_;
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_READ_H_

@ -0,0 +1,33 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
namespace chrome_pdf {
PDFiumMemBufferFileWrite::PDFiumMemBufferFileWrite() {
version = 1;
WriteBlock = &WriteBlockImpl;
}
PDFiumMemBufferFileWrite::~PDFiumMemBufferFileWrite() {
}
int PDFiumMemBufferFileWrite::WriteBlockImpl(FPDF_FILEWRITE* this_file_write,
const void* data,
unsigned long size) {
PDFiumMemBufferFileWrite* mem_buffer_file_write =
static_cast<PDFiumMemBufferFileWrite*>(this_file_write);
return mem_buffer_file_write->DoWriteBlock(data, size);
}
int PDFiumMemBufferFileWrite::DoWriteBlock(const void* data,
unsigned long size) {
buffer_.append(static_cast<const unsigned char*>(data), size);
return 1;
}
} // namespace chrome_pdf

@ -0,0 +1,34 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_WRITE_
#define PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_WRITE_
#include <string>
#include "third_party/pdfium/fpdfsdk/include/fpdfsave.h"
namespace chrome_pdf {
// Implementation of FPDF_FILEWRITE into a memory buffer.
class PDFiumMemBufferFileWrite : public FPDF_FILEWRITE {
public:
PDFiumMemBufferFileWrite();
~PDFiumMemBufferFileWrite();
const std::basic_string<unsigned char>& buffer() { return buffer_; }
size_t size() { return buffer_.size(); }
private:
int DoWriteBlock(const void* data, unsigned long size);
static int WriteBlockImpl(FPDF_FILEWRITE* this_file_write, const void* data,
unsigned long size);
std::basic_string<unsigned char> buffer_;
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_MEM_BUFFER_FILE_WRITE_

478
pdf/pdfium/pdfium_page.cc Normal file

@ -0,0 +1,478 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdfium/pdfium_page.h"
#include <math.h>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "pdf/pdfium/pdfium_engine.h"
// Used when doing hit detection.
#define kTolerance 20.0
// Dictionary Value key names for returning the accessible page content as JSON.
const char kPageWidth[] = "width";
const char kPageHeight[] = "height";
const char kPageTextBox[] = "textBox";
const char kTextBoxLeft[] = "left";
const char kTextBoxTop[] = "top";
const char kTextBoxWidth[] = "width";
const char kTextBoxHeight[] = "height";
const char kTextBoxFontSize[] = "fontSize";
const char kTextBoxNodes[] = "textNodes";
const char kTextNodeType[] = "type";
const char kTextNodeText[] = "text";
const char kTextNodeURL[] = "url";
const char kTextNodeTypeText[] = "text";
const char kTextNodeTypeURL[] = "url";
const char kDocLinkURLPrefix[] = "#page";
namespace chrome_pdf {
PDFiumPage::PDFiumPage(PDFiumEngine* engine,
int i,
const pp::Rect& r,
bool available)
: engine_(engine),
page_(NULL),
text_page_(NULL),
index_(i),
rect_(r),
calculated_links_(false),
available_(available) {
}
PDFiumPage::~PDFiumPage() {
Unload();
}
void PDFiumPage::Unload() {
if (text_page_) {
FPDFText_ClosePage(text_page_);
text_page_ = NULL;
}
if (page_) {
if (engine_->form()) {
FORM_OnBeforeClosePage(page_, engine_->form());
}
FPDF_ClosePage(page_);
page_ = NULL;
}
}
FPDF_PAGE PDFiumPage::GetPage() {
ScopedUnsupportedFeature scoped_unsupported_feature(engine_);
if (!available_)
return NULL;
if (!page_) {
page_ = FPDF_LoadPage(engine_->doc(), index_);
if (page_ && engine_->form()) {
FORM_OnAfterLoadPage(page_, engine_->form());
}
}
return page_;
}
FPDF_PAGE PDFiumPage::GetPrintPage() {
ScopedUnsupportedFeature scoped_unsupported_feature(engine_);
if (!available_)
return NULL;
if (!page_)
page_ = FPDF_LoadPage(engine_->doc(), index_);
return page_;
}
void PDFiumPage::ClosePrintPage() {
if (page_) {
FPDF_ClosePage(page_);
page_ = NULL;
}
}
FPDF_TEXTPAGE PDFiumPage::GetTextPage() {
if (!available_)
return NULL;
if (!text_page_)
text_page_ = FPDFText_LoadPage(GetPage());
return text_page_;
}
base::Value* PDFiumPage::GetAccessibleContentAsValue(int rotation) {
base::DictionaryValue* node = new base::DictionaryValue();
if (!available_)
return node;
double width = FPDF_GetPageWidth(GetPage());
double height = FPDF_GetPageHeight(GetPage());
base::ListValue* text = new base::ListValue();
int box_count = FPDFText_CountRects(GetTextPage(), 0, GetCharCount());
for (int i = 0; i < box_count; i++) {
double left, top, right, bottom;
FPDFText_GetRect(GetTextPage(), i, &left, &top, &right, &bottom);
text->Append(
GetTextBoxAsValue(height, left, top, right, bottom, rotation));
}
node->SetDouble(kPageWidth, width);
node->SetDouble(kPageHeight, height);
node->Set(kPageTextBox, text); // Takes ownership of |text|
return node;
}
base::Value* PDFiumPage::GetTextBoxAsValue(double page_height,
double left, double top,
double right, double bottom,
int rotation) {
base::string16 text_utf16;
int char_count =
FPDFText_GetBoundedText(GetTextPage(), left, top, right, bottom, NULL, 0);
if (char_count > 0) {
unsigned short* data = reinterpret_cast<unsigned short*>(
WriteInto(&text_utf16, char_count + 1));
FPDFText_GetBoundedText(GetTextPage(),
left, top, right, bottom,
data, char_count);
}
std::string text_utf8 = base::UTF16ToUTF8(text_utf16);
FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), left, top);
Area area;
std::vector<LinkTarget> targets;
if (link) {
targets.push_back(LinkTarget());
area = GetLinkTarget(link, &targets[0]);
} else {
pp::Rect rect(
PageToScreen(pp::Point(), 1.0, left, top, right, bottom, rotation));
GetLinks(rect, &targets);
area = targets.size() == 0 ? TEXT_AREA : WEBLINK_AREA;
}
int char_index = FPDFText_GetCharIndexAtPos(GetTextPage(), left, top,
kTolerance, kTolerance);
double font_size = FPDFText_GetFontSize(GetTextPage(), char_index);
base::DictionaryValue* node = new base::DictionaryValue();
node->SetDouble(kTextBoxLeft, left);
node->SetDouble(kTextBoxTop, page_height - top);
node->SetDouble(kTextBoxWidth, right - left);
node->SetDouble(kTextBoxHeight, top - bottom);
node->SetDouble(kTextBoxFontSize, font_size);
base::ListValue* text_nodes = new base::ListValue();
if (area == DOCLINK_AREA) {
std::string url = kDocLinkURLPrefix + base::IntToString(targets[0].page);
text_nodes->Append(CreateURLNode(text_utf8, url));
} else if (area == WEBLINK_AREA && link) {
text_nodes->Append(CreateURLNode(text_utf8, targets[0].url));
} else if (area == WEBLINK_AREA && !link) {
size_t start = 0;
for (size_t i = 0; i < targets.size(); ++i) {
// Remove the extra NULL character at end.
// Otherwise, find() will not return any matches.
if (targets[i].url.size() > 0 &&
targets[i].url[targets[i].url.size() - 1] == '\0') {
targets[i].url.resize(targets[i].url.size() - 1);
}
// There should only ever be one NULL character
DCHECK(targets[i].url[targets[i].url.size() - 1] != '\0');
// PDFium may change the case of generated links.
std::string lowerCaseURL = StringToLowerASCII(targets[i].url);
std::string lowerCaseText = StringToLowerASCII(text_utf8);
size_t pos = lowerCaseText.find(lowerCaseURL, start);
size_t length = targets[i].url.size();
if (pos == std::string::npos) {
// Check if the link is a "mailto:" URL
if (lowerCaseURL.compare(0, 7, "mailto:") == 0) {
pos = lowerCaseText.find(lowerCaseURL.substr(7), start);
length -= 7;
}
if (pos == std::string::npos) {
// No match has been found. This should never happen.
continue;
}
}
std::string before_text = text_utf8.substr(start, pos - start);
if (before_text.size() > 0)
text_nodes->Append(CreateTextNode(before_text));
std::string link_text = text_utf8.substr(pos, length);
text_nodes->Append(CreateURLNode(link_text, targets[i].url));
start = pos + length;
}
std::string before_text = text_utf8.substr(start);
if (before_text.size() > 0)
text_nodes->Append(CreateTextNode(before_text));
} else {
text_nodes->Append(CreateTextNode(text_utf8));
}
node->Set(kTextBoxNodes, text_nodes); // Takes ownership of |text_nodes|.
return node;
}
base::Value* PDFiumPage::CreateTextNode(std::string text) {
base::DictionaryValue* node = new base::DictionaryValue();
node->SetString(kTextNodeType, kTextNodeTypeText);
node->SetString(kTextNodeText, text);
return node;
}
base::Value* PDFiumPage::CreateURLNode(std::string text, std::string url) {
base::DictionaryValue* node = new base::DictionaryValue();
node->SetString(kTextNodeType, kTextNodeTypeURL);
node->SetString(kTextNodeText, text);
node->SetString(kTextNodeURL, url);
return node;
}
PDFiumPage::Area PDFiumPage::GetCharIndex(const pp::Point& point,
int rotation,
int* char_index,
LinkTarget* target) {
if (!available_)
return NONSELECTABLE_AREA;
pp::Point point2 = point - rect_.point();
double new_x, new_y;
FPDF_DeviceToPage(GetPage(), 0, 0, rect_.width(), rect_.height(),
rotation, point2.x(), point2.y(), &new_x, &new_y);
int rv = FPDFText_GetCharIndexAtPos(
GetTextPage(), new_x, new_y, kTolerance, kTolerance);
*char_index = rv;
FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), new_x, new_y);
if (link) {
// We don't handle all possible link types of the PDF. For example,
// launch actions, cross-document links, etc.
// In that case, GetLinkTarget() will return NONSELECTABLE_AREA
// and we should proceed with area detection.
PDFiumPage::Area area = GetLinkTarget(link, target);
if (area != PDFiumPage::NONSELECTABLE_AREA)
return area;
}
if (rv < 0)
return NONSELECTABLE_AREA;
return GetLink(*char_index, target) != -1 ? WEBLINK_AREA : TEXT_AREA;
}
base::char16 PDFiumPage::GetCharAtIndex(int index) {
if (!available_)
return L'\0';
return static_cast<base::char16>(FPDFText_GetUnicode(GetTextPage(), index));
}
int PDFiumPage::GetCharCount() {
if (!available_)
return 0;
return FPDFText_CountChars(GetTextPage());
}
PDFiumPage::Area PDFiumPage::GetLinkTarget(
FPDF_LINK link, PDFiumPage::LinkTarget* target) {
FPDF_DEST dest = FPDFLink_GetDest(engine_->doc(), link);
if (dest != NULL)
return GetDestinationTarget(dest, target);
FPDF_ACTION action = FPDFLink_GetAction(link);
if (action) {
switch (FPDFAction_GetType(action)) {
case PDFACTION_GOTO: {
FPDF_DEST dest = FPDFAction_GetDest(engine_->doc(), action);
if (dest)
return GetDestinationTarget(dest, target);
// TODO(gene): We don't fully support all types of the in-document
// links. Need to implement that. There is a bug to track that:
// http://code.google.com/p/chromium/issues/detail?id=55776
} break;
case PDFACTION_URI: {
if (target) {
size_t buffer_size =
FPDFAction_GetURIPath(engine_->doc(), action, NULL, 0);
if (buffer_size > 1) {
void* data = WriteInto(&target->url, buffer_size);
FPDFAction_GetURIPath(engine_->doc(), action, data, buffer_size);
}
}
return WEBLINK_AREA;
} break;
// TODO(gene): We don't support PDFACTION_REMOTEGOTO and PDFACTION_LAUNCH
// at the moment.
}
}
return NONSELECTABLE_AREA;
}
PDFiumPage::Area PDFiumPage::GetDestinationTarget(
FPDF_DEST destination, PDFiumPage::LinkTarget* target) {
int page_index = FPDFDest_GetPageIndex(engine_->doc(), destination);
if (target) {
target->page = page_index;
}
return DOCLINK_AREA;
}
int PDFiumPage::GetLink(int char_index, PDFiumPage::LinkTarget* target) {
if (!available_)
return -1;
CalculateLinks();
// Get the bounding box of the rect again, since it might have moved because
// of the tolerance above.
double left, right, bottom, top;
FPDFText_GetCharBox(GetTextPage(), char_index, &left, &right, &bottom, &top);
pp::Point origin(
PageToScreen(pp::Point(), 1.0, left, top, right, bottom, 0).point());
for (size_t i = 0; i < links_.size(); ++i) {
for (size_t j = 0; j < links_[i].rects.size(); ++j) {
if (links_[i].rects[j].Contains(origin)) {
if (target)
target->url = links_[i].url;
return i;
}
}
}
return -1;
}
std::vector<int> PDFiumPage::GetLinks(pp::Rect text_area,
std::vector<LinkTarget>* targets) {
if (!available_)
return std::vector<int>();
CalculateLinks();
std::vector<int> links;
for (size_t i = 0; i < links_.size(); ++i) {
for (size_t j = 0; j < links_[i].rects.size(); ++j) {
if (links_[i].rects[j].Intersects(text_area)) {
if (targets) {
LinkTarget target;
target.url = links_[i].url;
targets->push_back(target);
}
links.push_back(i);
}
}
}
return links;
}
void PDFiumPage::CalculateLinks() {
if (calculated_links_)
return;
calculated_links_ = true;
FPDF_PAGELINK links = FPDFLink_LoadWebLinks(GetTextPage());
int count = FPDFLink_CountWebLinks(links);
for (int i = 0; i < count; ++i) {
base::string16 url;
int url_length = FPDFLink_GetURL(links, i, NULL, 0);
if (url_length > 0) {
unsigned short* data =
reinterpret_cast<unsigned short*>(WriteInto(&url, url_length + 1));
FPDFLink_GetURL(links, i, data, url_length);
}
Link link;
link.url = base::UTF16ToUTF8(url);
// If the link cannot be converted to a pp::Var, then it is not possible to
// pass it to JS. In this case, ignore the link like other PDF viewers.
// See http://crbug.com/312882 for an example.
pp::Var link_var(link.url);
if (!link_var.is_string())
continue;
// Make sure all the characters in the URL are valid per RFC 1738.
// http://crbug.com/340326 has a sample bad PDF.
// GURL does not work correctly, e.g. it just strips \t \r \n.
bool is_invalid_url = false;
for (size_t j = 0; j < link.url.length(); ++j) {
// Control characters are not allowed.
// 0x7F is also a control character.
// 0x80 and above are not in US-ASCII.
if (link.url[j] < ' ' || link.url[j] >= '\x7F') {
is_invalid_url = true;
break;
}
}
if (is_invalid_url)
continue;
int rect_count = FPDFLink_CountRects(links, i);
for (int j = 0; j < rect_count; ++j) {
double left, top, right, bottom;
FPDFLink_GetRect(links, i, j, &left, &top, &right, &bottom);
link.rects.push_back(
PageToScreen(pp::Point(), 1.0, left, top, right, bottom, 0));
}
links_.push_back(link);
}
FPDFLink_CloseWebLinks(links);
}
pp::Rect PDFiumPage::PageToScreen(const pp::Point& offset,
double zoom,
double left,
double top,
double right,
double bottom,
int rotation) {
if (!available_)
return pp::Rect();
int new_left, new_top, new_right, new_bottom;
FPDF_PageToDevice(
page_,
static_cast<int>((rect_.x() - offset.x()) * zoom),
static_cast<int>((rect_.y() - offset.y()) * zoom),
static_cast<int>(ceil(rect_.width() * zoom)),
static_cast<int>(ceil(rect_.height() * zoom)),
rotation, left, top, &new_left, &new_top);
FPDF_PageToDevice(
page_,
static_cast<int>((rect_.x() - offset.x()) * zoom),
static_cast<int>((rect_.y() - offset.y()) * zoom),
static_cast<int>(ceil(rect_.width() * zoom)),
static_cast<int>(ceil(rect_.height() * zoom)),
rotation, right, bottom, &new_right, &new_bottom);
// If the PDF is rotated, the horizontal/vertical coordinates could be
// flipped. See
// http://www.netl.doe.gov/publications/proceedings/03/ubc/presentations/Goeckner-pres.pdf
if (new_right < new_left)
std::swap(new_right, new_left);
if (new_bottom < new_top)
std::swap(new_bottom, new_top);
return pp::Rect(
new_left, new_top, new_right - new_left + 1, new_bottom - new_top + 1);
}
PDFiumPage::Link::Link() {
}
PDFiumPage::Link::~Link() {
}
} // namespace chrome_pdf

136
pdf/pdfium/pdfium_page.h Normal file

@ -0,0 +1,136 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_PAGE_H_
#define PDF_PDFIUM_PDFIUM_PAGE_H_
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "ppapi/cpp/rect.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfdoc.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfformfill.h"
#include "third_party/pdfium/fpdfsdk/include/fpdftext.h"
namespace base {
class Value;
}
namespace chrome_pdf {
class PDFiumEngine;
// Wrapper around a page from the document.
class PDFiumPage {
public:
PDFiumPage(PDFiumEngine* engine,
int i,
const pp::Rect& r,
bool available);
~PDFiumPage();
// Unloads the PDFium data for this page from memory.
void Unload();
// Gets the FPDF_PAGE for this page, loading and parsing it if necessary.
FPDF_PAGE GetPage();
//Get the FPDF_PAGE for printing.
FPDF_PAGE GetPrintPage();
//Close the printing page.
void ClosePrintPage();
// Returns FPDF_TEXTPAGE for the page, loading and parsing it if necessary.
FPDF_TEXTPAGE GetTextPage();
// Returns a DictionaryValue version of the page.
base::Value* GetAccessibleContentAsValue(int rotation);
enum Area {
NONSELECTABLE_AREA,
TEXT_AREA,
WEBLINK_AREA, // Area is a hyperlink.
DOCLINK_AREA, // Area is a link to a different part of the same document.
};
struct LinkTarget {
// We are using std::string here which have a copy contructor.
// That prevents us from using union here.
std::string url; // Valid for WEBLINK_AREA only.
int page; // Valid for DOCLINK_AREA only.
};
// Given a point in the document that's in this page, returns its character
// index if it's near a character, and also the type of text.
// Target is optional. It will be filled in for WEBLINK_AREA or
// DOCLINK_AREA only.
Area GetCharIndex(const pp::Point& point, int rotation, int* char_index,
LinkTarget* target);
// Gets the character at the given index.
base::char16 GetCharAtIndex(int index);
// Gets the number of characters in the page.
int GetCharCount();
// Converts from page coordinates to screen coordinates.
pp::Rect PageToScreen(const pp::Point& offset,
double zoom,
double left,
double top,
double right,
double bottom,
int rotation);
int index() const { return index_; }
pp::Rect rect() const { return rect_; }
void set_rect(const pp::Rect& r) { rect_ = r; }
bool available() const { return available_; }
void set_available(bool available) { available_ = available; }
void set_calculated_links(bool calculated_links) {
calculated_links_ = calculated_links;
}
private:
// Returns a link index if the given character index is over a link, or -1
// otherwise.
int GetLink(int char_index, LinkTarget* target);
// Returns the link indices if the given rect intersects a link rect, or an
// empty vector otherwise.
std::vector<int> GetLinks(pp::Rect text_area,
std::vector<LinkTarget>* targets);
// Calculate the locations of any links on the page.
void CalculateLinks();
// Returns link type and target associated with a link. Returns
// NONSELECTABLE_AREA if link detection failed.
Area GetLinkTarget(FPDF_LINK link, LinkTarget* target);
// Returns target associated with a destination.
Area GetDestinationTarget(FPDF_DEST destination, LinkTarget* target);
// Returns the text in the supplied box as a Value Node
base::Value* GetTextBoxAsValue(double page_height, double left, double top,
double right, double bottom, int rotation);
// Helper functions for JSON generation
base::Value* CreateTextNode(std::string text);
base::Value* CreateURLNode(std::string text, std::string url);
struct Link {
Link();
~Link();
std::string url;
// Bounding rectangles of characters.
std::vector<pp::Rect> rects;
};
PDFiumEngine* engine_;
FPDF_PAGE page_;
FPDF_TEXTPAGE text_page_;
int index_;
pp::Rect rect_;
bool calculated_links_;
std::vector<Link> links_;
bool available_;
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_PAGE_H_

@ -0,0 +1,79 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdfium/pdfium_range.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
namespace chrome_pdf {
PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count)
: page_(page),
char_index_(char_index),
char_count_(char_count),
cached_screen_rects_zoom_(0) {
}
PDFiumRange::~PDFiumRange() {
}
void PDFiumRange::SetCharCount(int char_count) {
char_count_ = char_count;
cached_screen_rects_offset_ = pp::Point();
cached_screen_rects_zoom_ = 0;
}
std::vector<pp::Rect> PDFiumRange::GetScreenRects(const pp::Point& offset,
double zoom,
int rotation) {
if (offset == cached_screen_rects_offset_ &&
zoom == cached_screen_rects_zoom_) {
return cached_screen_rects_;
}
cached_screen_rects_.clear();
cached_screen_rects_offset_ = offset;
cached_screen_rects_zoom_ = zoom;
int char_index = char_index_;
int char_count = char_count_;
if (char_count < 0) {
char_count *= -1;
char_index -= char_count - 1;
}
int count = FPDFText_CountRects(page_->GetTextPage(), char_index, char_count);
for (int i = 0; i < count; ++i) {
double left, top, right, bottom;
FPDFText_GetRect(page_->GetTextPage(), i, &left, &top, &right, &bottom);
cached_screen_rects_.push_back(
page_->PageToScreen(offset, zoom, left, top, right, bottom, rotation));
}
return cached_screen_rects_;
}
base::string16 PDFiumRange::GetText() {
int index = char_index_;
int count = char_count_;
if (!count)
return base::string16();
if (count < 0) {
count *= -1;
index -= count - 1;
}
base::string16 rv;
unsigned short* data =
reinterpret_cast<unsigned short*>(WriteInto(&rv, count + 1));
if (data) {
int written = FPDFText_GetText(page_->GetTextPage(), index, count, data);
rv.reserve(written);
}
return rv;
}
} // namespace chrome_pdf

54
pdf/pdfium/pdfium_range.h Normal file

@ -0,0 +1,54 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_RANGE_H_
#define PDF_PDFIUM_PDFIUM_RANGE_H_
#include <string>
#include <vector>
#include "base/strings/string16.h"
#include "pdf/pdfium/pdfium_page.h"
#include "ppapi/cpp/rect.h"
namespace chrome_pdf {
// Describes location of a string of characters.
class PDFiumRange {
public:
PDFiumRange(PDFiumPage* page, int char_index, int char_count);
~PDFiumRange();
// Update how many characters are in the selection. Could be negative if
// backwards.
void SetCharCount(int char_count);
int page_index() const { return page_->index(); }
int char_index() const { return char_index_; }
int char_count() const { return char_count_; }
// Gets bounding rectangles of range in screen coordinates.
std::vector<pp::Rect> GetScreenRects(const pp::Point& offset,
double zoom,
int rotation);
// Gets the string of characters in this range.
base::string16 GetText();
private:
PDFiumPage* page_;
// Index of first character.
int char_index_;
// How many characters are part of this range (negative if backwards).
int char_count_;
// Cache of ScreenRect, and the associated variables used when caching it.
std::vector<pp::Rect> cached_screen_rects_;
pp::Point cached_screen_rects_offset_;
double cached_screen_rects_zoom_;
};
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_RANGE_H_

312
pdf/pdfium/pdfium_test.cc Normal file

@ -0,0 +1,312 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <list>
#include <string>
#include <utility>
#include "base/at_exit.h"
#include "base/i18n/icu_util.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_dataavail.h"
#include "third_party/pdfium/fpdfsdk/include/fpdf_ext.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfformfill.h"
#include "third_party/pdfium/fpdfsdk/include/fpdftext.h"
#include "third_party/pdfium/fpdfsdk/include/fpdfview.h"
#ifdef _WIN32
#define snprintf _snprintf
/* in Windows, rb for open and read binary file */
#define FOPEN_READ "rb"
#else
#define FOPEN_READ "r"
#endif
static void write_file(const char* pdf_name, int num,
const char* buffer, int stride, int width, int height) {
if (stride < 0 || width < 0 || height < 0)
return;
if (height > 0 && width > INT_MAX / height)
return;
int out_len = width * height;
if (out_len > INT_MAX / 3)
return;
out_len *= 3;
char filename[256];
snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
FILE* fp = fopen(filename, "w");
if (!fp)
return;
fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
// Source data is B, G, R, unused.
// Dest data is R, G, B.
char* result = new char[out_len];
if (result) {
int h, w;
for (h = 0; h < height; ++h) {
const char* src_line = buffer + (stride * h);
char* dest_line = result + (width * h * 3);
for (w = 0; w < width; ++w) {
// R
dest_line[w * 3] = src_line[(w * 4) + 2];
// G
dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
// B
dest_line[(w * 3) + 2] = src_line[w * 4];
}
}
fwrite(result, out_len, 1, fp);
delete [] result;
}
fclose(fp);
}
int Form_Alert(IPDF_JSPLATFORM*, FPDF_WIDESTRING, FPDF_WIDESTRING, int, int) {
printf("Form_Alert called.\n");
return 0;
}
void Unsupported_Handler(UNSUPPORT_INFO*, int type) {
std::string feature = "Unknown";
switch (type) {
case FPDF_UNSP_DOC_XFAFORM:
feature = "XFA";
break;
case FPDF_UNSP_DOC_PORTABLECOLLECTION:
feature = "Portfolios_Packages";
break;
case FPDF_UNSP_DOC_ATTACHMENT:
case FPDF_UNSP_ANNOT_ATTACHMENT:
feature = "Attachment";
break;
case FPDF_UNSP_DOC_SECURITY:
feature = "Rights_Management";
break;
case FPDF_UNSP_DOC_SHAREDREVIEW:
feature = "Shared_Review";
break;
case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
feature = "Shared_Form";
break;
case FPDF_UNSP_ANNOT_3DANNOT:
feature = "3D";
break;
case FPDF_UNSP_ANNOT_MOVIE:
feature = "Movie";
break;
case FPDF_UNSP_ANNOT_SOUND:
feature = "Sound";
break;
case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
feature = "Screen";
break;
case FPDF_UNSP_ANNOT_SIG:
feature = "Digital_Signature";
break;
}
printf("Unsupported feature: %s.\n", feature.c_str());
}
bool ParseCommandLine(int argc, const char* argv[], bool* write_images,
std::list<const char*>* files) {
*write_images = false;
files->clear();
int cur_arg = 1;
if (cur_arg < argc &&
strcmp(argv[cur_arg], "--write_images") == 0) {
*write_images = true;
cur_arg++;
}
if (cur_arg >= argc)
return false;
for (int i = cur_arg; i < argc; i++)
files->push_back(argv[i]);
return true;
}
class TestLoader {
public:
TestLoader(const char* pBuf, size_t len);
const char* m_pBuf;
size_t m_Len;
};
TestLoader::TestLoader(const char* pBuf, size_t len)
: m_pBuf(pBuf), m_Len(len) {
}
int Get_Block(void* param, unsigned long pos, unsigned char* pBuf,
unsigned long size) {
TestLoader* pLoader = (TestLoader*) param;
if (pos + size < pos || pos + size > pLoader->m_Len) return 0;
memcpy(pBuf, pLoader->m_pBuf + pos, size);
return 1;
}
bool Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
return true;
}
void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
}
void RenderPdf(const char* name, const char* pBuf, size_t len,
bool write_images) {
printf("Rendering PDF file %s.\n", name);
IPDF_JSPLATFORM platform_callbacks;
memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
platform_callbacks.version = 1;
platform_callbacks.app_alert = Form_Alert;
FPDF_FORMFILLINFO form_callbacks;
memset(&form_callbacks, '\0', sizeof(form_callbacks));
form_callbacks.version = 1;
form_callbacks.m_pJsPlatform = &platform_callbacks;
TestLoader loader(pBuf, len);
FPDF_FILEACCESS file_access;
memset(&file_access, '\0', sizeof(file_access));
file_access.m_FileLen = len;
file_access.m_GetBlock = Get_Block;
file_access.m_Param = &loader;
FX_FILEAVAIL file_avail;
memset(&file_avail, '\0', sizeof(file_avail));
file_avail.version = 1;
file_avail.IsDataAvail = Is_Data_Avail;
FX_DOWNLOADHINTS hints;
memset(&hints, '\0', sizeof(hints));
hints.version = 1;
hints.AddSegment = Add_Segment;
FPDF_DOCUMENT doc;
FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access);
(void) FPDFAvail_IsDocAvail(pdf_avail, &hints);
if (!FPDFAvail_IsLinearized(pdf_avail)) {
printf("Non-linearized path...\n");
doc = FPDF_LoadCustomDocument(&file_access, NULL);
} else {
printf("Linearized path...\n");
doc = FPDFAvail_GetDocument(pdf_avail, NULL);
}
(void) FPDF_GetDocPermissions(doc);
(void) FPDFAvail_IsFormAvail(pdf_avail, &hints);
FPDF_FORMHANDLE form = FPDFDOC_InitFormFillEnviroument(doc, &form_callbacks);
FPDF_SetFormFieldHighlightColor(form, 0, 0xFFE4DD);
FPDF_SetFormFieldHighlightAlpha(form, 100);
int first_page = FPDFAvail_GetFirstPageNum(doc);
(void) FPDFAvail_IsPageAvail(pdf_avail, first_page, &hints);
int page_count = FPDF_GetPageCount(doc);
for (int i = 0; i < page_count; ++i) {
(void) FPDFAvail_IsPageAvail(pdf_avail, i, &hints);
}
FORM_DoDocumentJSAction(form);
FORM_DoDocumentOpenAction(form);
for (int i = 0; i < page_count; ++i) {
FPDF_PAGE page = FPDF_LoadPage(doc, i);
FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
FORM_OnAfterLoadPage(page, form);
FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN);
int width = static_cast<int>(FPDF_GetPageWidth(page));
int height = static_cast<int>(FPDF_GetPageHeight(page));
FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, 0);
FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 255, 255, 255, 255);
FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0);
if (write_images) {
const char* buffer = reinterpret_cast<const char*>(
FPDFBitmap_GetBuffer(bitmap));
int stride = FPDFBitmap_GetStride(bitmap);
write_file(name, i, buffer, stride, width, height);
}
FPDFBitmap_Destroy(bitmap);
FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);
FORM_OnBeforeClosePage(page, form);
FPDFText_ClosePage(text_page);
FPDF_ClosePage(page);
}
FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC);
FPDFDOC_ExitFormFillEnviroument(form);
FPDF_CloseDocument(doc);
FPDFAvail_Destroy(pdf_avail);
printf("Loaded, parsed and rendered %d pages.\n", page_count);
}
int main(int argc, const char* argv[]) {
base::AtExitManager exit_manager;
base::i18n::InitializeICU();
bool write_images = false;
std::list<const char*> files;
if (!ParseCommandLine(argc, argv, &write_images, &files)) {
printf("Usage is: test [--write_images] /path/to/pdf\n");
printf("--write_images - to write page images <pdf-name>.<page-number>.ppm\n");
return 1;
}
FPDF_InitLibrary(NULL);
UNSUPPORT_INFO unsuppored_info;
memset(&unsuppored_info, '\0', sizeof(unsuppored_info));
unsuppored_info.version = 1;
unsuppored_info.FSDK_UnSupport_Handler = Unsupported_Handler;
FSDK_SetUnSpObjProcessHandler(&unsuppored_info);
while (!files.empty()) {
const char* filename = files.front();
files.pop_front();
FILE* file = fopen(filename, FOPEN_READ);
if (!file) {
fprintf(stderr, "Failed to open: %s\n", filename);
continue;
}
(void) fseek(file, 0, SEEK_END);
size_t len = ftell(file);
(void) fseek(file, 0, SEEK_SET);
char* pBuf = (char*) malloc(len);
size_t ret = fread(pBuf, 1, len, file);
(void) fclose(file);
if (ret != len) {
fprintf(stderr, "Failed to read: %s\n", filename);
} else {
RenderPdf(filename, pBuf, len, write_images);
}
free(pBuf);
}
FPDF_DestroyLibrary();
return 0;
}

162
pdf/preview_mode_client.cc Normal file

@ -0,0 +1,162 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/preview_mode_client.h"
#include "base/logging.h"
#include "pdf/instance.h"
namespace chrome_pdf {
PreviewModeClient::PreviewModeClient(Client* client)
: client_(client) {
}
void PreviewModeClient::DocumentSizeUpdated(const pp::Size& size) {
}
void PreviewModeClient::Invalidate(const pp::Rect& rect) {
NOTREACHED();
}
void PreviewModeClient::Scroll(const pp::Point& point) {
NOTREACHED();
}
void PreviewModeClient::ScrollToX(int position) {
NOTREACHED();
}
void PreviewModeClient::ScrollToY(int position) {
NOTREACHED();
}
void PreviewModeClient::ScrollToPage(int page) {
NOTREACHED();
}
void PreviewModeClient::NavigateTo(const std::string& url,
bool open_in_new_tab) {
NOTREACHED();
}
void PreviewModeClient::UpdateCursor(PP_CursorType_Dev cursor) {
NOTREACHED();
}
void PreviewModeClient::UpdateTickMarks(
const std::vector<pp::Rect>& tickmarks) {
NOTREACHED();
}
void PreviewModeClient::NotifyNumberOfFindResultsChanged(int total,
bool final_result) {
NOTREACHED();
}
void PreviewModeClient::NotifySelectedFindResultChanged(
int current_find_index) {
NOTREACHED();
}
void PreviewModeClient::GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback) {
callback.Run(PP_ERROR_FAILED);
}
void PreviewModeClient::Alert(const std::string& message) {
NOTREACHED();
}
bool PreviewModeClient::Confirm(const std::string& message) {
NOTREACHED();
return false;
}
std::string PreviewModeClient::Prompt(const std::string& question,
const std::string& default_answer) {
NOTREACHED();
return std::string();
}
std::string PreviewModeClient::GetURL() {
NOTREACHED();
return std::string();
}
void PreviewModeClient::Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body) {
NOTREACHED();
}
void PreviewModeClient::Print() {
NOTREACHED();
}
void PreviewModeClient::SubmitForm(const std::string& url,
const void* data,
int length) {
NOTREACHED();
}
std::string PreviewModeClient::ShowFileSelectionDialog() {
NOTREACHED();
return std::string();
}
pp::URLLoader PreviewModeClient::CreateURLLoader() {
NOTREACHED();
return pp::URLLoader();
}
void PreviewModeClient::ScheduleCallback(int id, int delay_in_ms) {
NOTREACHED();
}
void PreviewModeClient::SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive,
std::vector<SearchStringResult>* results) {
NOTREACHED();
}
void PreviewModeClient::DocumentPaintOccurred() {
NOTREACHED();
}
void PreviewModeClient::DocumentLoadComplete(int page_count) {
client_->PreviewDocumentLoadComplete();
}
void PreviewModeClient::DocumentLoadFailed() {
client_->PreviewDocumentLoadFailed();
}
pp::Instance* PreviewModeClient::GetPluginInstance() {
NOTREACHED();
return NULL;
}
void PreviewModeClient::DocumentHasUnsupportedFeature(
const std::string& feature) {
NOTREACHED();
}
void PreviewModeClient::DocumentLoadProgress(uint32 available,
uint32 doc_size) {
}
void PreviewModeClient::FormTextFieldFocusChange(bool in_focus) {
NOTREACHED();
}
bool PreviewModeClient::IsPrintPreview() {
NOTREACHED();
return false;
}
} // namespace chrome_pdf

77
pdf/preview_mode_client.h Normal file

@ -0,0 +1,77 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PREVIEW_MODE_CLIENT_H_
#define PDF_PREVIEW_MODE_CLIENT_H_
#include <string>
#include <vector>
#include "pdf/pdf_engine.h"
namespace chrome_pdf {
// The interface that's provided to the print preview rendering engine.
class PreviewModeClient : public PDFEngine::Client {
public:
class Client {
public:
virtual void PreviewDocumentLoadFailed() = 0;
virtual void PreviewDocumentLoadComplete() = 0;
};
explicit PreviewModeClient(Client* client);
virtual ~PreviewModeClient() {}
// PDFEngine::Client implementation.
virtual void DocumentSizeUpdated(const pp::Size& size);
virtual void Invalidate(const pp::Rect& rect);
virtual void Scroll(const pp::Point& point);
virtual void ScrollToX(int position);
virtual void ScrollToY(int position);
virtual void ScrollToPage(int page);
virtual void NavigateTo(const std::string& url, bool open_in_new_tab);
virtual void UpdateCursor(PP_CursorType_Dev cursor);
virtual void UpdateTickMarks(const std::vector<pp::Rect>& tickmarks);
virtual void NotifyNumberOfFindResultsChanged(int total,
bool final_result);
virtual void NotifySelectedFindResultChanged(int current_find_index);
virtual void GetDocumentPassword(
pp::CompletionCallbackWithOutput<pp::Var> callback);
virtual void Alert(const std::string& message);
virtual bool Confirm(const std::string& message);
virtual std::string Prompt(const std::string& question,
const std::string& default_answer);
virtual std::string GetURL();
virtual void Email(const std::string& to,
const std::string& cc,
const std::string& bcc,
const std::string& subject,
const std::string& body);
virtual void Print();
virtual void SubmitForm(const std::string& url,
const void* data,
int length);
virtual std::string ShowFileSelectionDialog();
virtual pp::URLLoader CreateURLLoader();
virtual void ScheduleCallback(int id, int delay_in_ms);
virtual void SearchString(const base::char16* string,
const base::char16* term,
bool case_sensitive,
std::vector<SearchStringResult>* results);
virtual void DocumentPaintOccurred();
virtual void DocumentLoadComplete(int page_count);
virtual void DocumentLoadFailed();
virtual pp::Instance* GetPluginInstance();
virtual void DocumentHasUnsupportedFeature(const std::string& feature);
virtual void DocumentLoadProgress(uint32 available, uint32 doc_size);
virtual void FormTextFieldFocusChange(bool in_focus);
virtual bool IsPrintPreview();
private:
Client* client_;
};
} // namespace chrome_pdf
#endif // PDF_PREVIEW_MODE_CLIENT_H_

283
pdf/progress_control.cc Normal file

@ -0,0 +1,283 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/progress_control.h"
#include <algorithm>
#include "base/logging.h"
#include "pdf/draw_utils.h"
#include "pdf/resource_consts.h"
#include "ppapi/cpp/dev/font_dev.h"
namespace chrome_pdf {
const double ProgressControl::kCompleted = 100.0;
// There is a bug outputting text with alpha 0xFF (opaque) to an intermediate
// image. It outputs alpha channgel of the text pixels to 0xFF (transparent).
// And it breaks next alpha blending.
// For now, let's use alpha 0xFE to work around this bug.
// TODO(gene): investigate this bug.
const uint32 kProgressTextColor = 0xFEDDE6FC;
const uint32 kProgressTextSize = 16;
const uint32 kImageTextSpacing = 8;
const uint32 kTopPadding = 8;
const uint32 kBottomPadding = 12;
const uint32 kLeftPadding = 10;
const uint32 kRightPadding = 10;
int ScaleInt(int val, float scale) {
return static_cast<int>(val * scale);
}
ProgressControl::ProgressControl()
: progress_(0.0),
device_scale_(1.0) {
}
ProgressControl::~ProgressControl() {
}
bool ProgressControl::CreateProgressControl(
uint32 id,
bool visible,
Control::Owner* delegate,
double progress,
float device_scale,
const std::vector<pp::ImageData>& images,
const pp::ImageData& background,
const std::string& text) {
progress_ = progress;
text_ = text;
bool res = Control::Create(id, pp::Rect(), visible, delegate);
if (res)
Reconfigure(background, images, device_scale);
return res;
}
void ProgressControl::Reconfigure(const pp::ImageData& background,
const std::vector<pp::ImageData>& images,
float device_scale) {
DCHECK(images.size() != 0);
images_ = images;
background_ = background;
device_scale_ = device_scale;
pp::Size ctrl_size;
CalculateLayout(owner()->GetInstance(), images_, background_, text_,
device_scale_, &ctrl_size, &image_rc_, &text_rc_);
pp::Rect rc(pp::Point(), ctrl_size);
Control::SetRect(rc, false);
PrepareBackground();
}
// static
void ProgressControl::CalculateLayout(pp::Instance* instance,
const std::vector<pp::ImageData>& images,
const pp::ImageData& background,
const std::string& text,
float device_scale,
pp::Size* ctrl_size,
pp::Rect* image_rc,
pp::Rect* text_rc) {
DCHECK(images.size() != 0);
int image_width = 0;
int image_height = 0;
for (size_t i = 0; i < images.size(); i++) {
image_width = std::max(image_width, images[i].size().width());
image_height = std::max(image_height, images[i].size().height());
}
pp::FontDescription_Dev description;
description.set_family(PP_FONTFAMILY_SANSSERIF);
description.set_size(ScaleInt(kProgressTextSize, device_scale));
description.set_weight(PP_FONTWEIGHT_BOLD);
pp::Font_Dev font(instance, description);
int text_length = font.MeasureSimpleText(text);
pp::FontDescription_Dev desc;
PP_FontMetrics_Dev metrics;
font.Describe(&desc, &metrics);
int text_height = metrics.height;
*ctrl_size = pp::Size(
image_width + text_length +
ScaleInt(kImageTextSpacing + kLeftPadding + kRightPadding, device_scale),
std::max(image_height, text_height) +
ScaleInt(kTopPadding + kBottomPadding, device_scale));
int offset_x = 0;
int offset_y = 0;
if (ctrl_size->width() < background.size().width()) {
offset_x += (background.size().width() - ctrl_size->width()) / 2;
ctrl_size->set_width(background.size().width());
}
if (ctrl_size->height() < background.size().height()) {
offset_y += (background.size().height() - ctrl_size->height()) / 2;
ctrl_size->set_height(background.size().height());
}
*image_rc = pp::Rect(ScaleInt(kLeftPadding, device_scale) + offset_x,
ScaleInt(kTopPadding, device_scale) + offset_y,
image_width,
image_height);
*text_rc = pp::Rect(
ctrl_size->width() - text_length -
ScaleInt(kRightPadding, device_scale) - offset_x,
(ctrl_size->height() - text_height) / 2,
text_length,
text_height);
}
size_t ProgressControl::GetImageIngex() const {
return static_cast<size_t>((progress_ / 100.0) * images_.size());
}
void ProgressControl::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
if (!visible())
return;
pp::Rect draw_rc = rect().Intersect(rc);
if (draw_rc.IsEmpty())
return;
pp::ImageData buffer(owner()->GetInstance(), ctrl_background_.format(),
ctrl_background_.size(), false);
CopyImage(ctrl_background_, pp::Rect(ctrl_background_.size()),
&buffer, pp::Rect(ctrl_background_.size()), false);
size_t index = GetImageIngex();
if (index >= images_.size())
index = images_.size() - 1;
AlphaBlend(images_[index],
pp::Rect(images_[index].size()),
&buffer,
image_rc_.point(),
kOpaqueAlpha);
pp::Rect image_draw_rc(draw_rc);
image_draw_rc.Offset(-rect().x(), -rect().y());
AlphaBlend(buffer,
image_draw_rc,
image_data,
draw_rc.point(),
transparency());
}
void ProgressControl::SetProgress(double progress) {
size_t old_index = GetImageIngex();
progress_ = progress;
size_t new_index = GetImageIngex();
if (progress_ >= kCompleted) {
progress_ = kCompleted;
owner()->OnEvent(id(), EVENT_ID_PROGRESS_COMPLETED, NULL);
}
if (visible() && old_index != new_index)
owner()->Invalidate(id(), rect());
}
void ProgressControl::PrepareBackground() {
AdjustBackground();
pp::FontDescription_Dev description;
description.set_family(PP_FONTFAMILY_SANSSERIF);
description.set_size(ScaleInt(kProgressTextSize, device_scale_));
description.set_weight(PP_FONTWEIGHT_BOLD);
pp::Font_Dev font(owner()->GetInstance(), description);
pp::FontDescription_Dev desc;
PP_FontMetrics_Dev metrics;
font.Describe(&desc, &metrics);
pp::Point text_origin = pp::Point(text_rc_.x(),
(text_rc_.y() + text_rc_.bottom() + metrics.x_height) / 2);
font.DrawTextAt(&ctrl_background_, pp::TextRun_Dev(text_), text_origin,
kProgressTextColor, pp::Rect(ctrl_background_.size()), false);
}
void ProgressControl::AdjustBackground() {
ctrl_background_ = pp::ImageData(owner()->GetInstance(),
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
rect().size(),
false);
if (rect().size() == background_.size()) {
CopyImage(background_, pp::Rect(background_.size()),
&ctrl_background_, pp::Rect(ctrl_background_.size()), false);
return;
}
// We need to stretch background to new dimentions. To do so, we split
// background into 9 different parts. We copy corner rects (1,3,7,9) as is,
// stretch rectangles between corners (2,4,6,8) in 1 dimention, and
// stretch center rect (5) in 2 dimentions.
// |---|---|---|
// | 1 | 2 | 3 |
// |---|---|---|
// | 4 | 5 | 6 |
// |---|---|---|
// | 7 | 8 | 9 |
// |---|---|---|
int slice_x = background_.size().width() / 3;
int slice_y = background_.size().height() / 3;
// Copy rect 1
pp::Rect src_rc(0, 0, slice_x, slice_y);
pp::Rect dest_rc(0, 0, slice_x, slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, false);
// Copy rect 3
src_rc.set_x(background_.size().width() - slice_x);
dest_rc.set_x(ctrl_background_.size().width() - slice_x);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, false);
// Copy rect 9
src_rc.set_y(background_.size().height() - slice_y);
dest_rc.set_y(ctrl_background_.size().height() - slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, false);
// Copy rect 7
src_rc.set_x(0);
dest_rc.set_x(0);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, false);
// Stretch rect 2
src_rc = pp::Rect(
slice_x, 0, background_.size().width() - 2 * slice_x, slice_y);
dest_rc = pp::Rect(
slice_x, 0, ctrl_background_.size().width() - 2 * slice_x, slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, true);
// Copy rect 8
src_rc.set_y(background_.size().height() - slice_y);
dest_rc.set_y(ctrl_background_.size().height() - slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, true);
// Stretch rect 4
src_rc = pp::Rect(
0, slice_y, slice_x, background_.size().height() - 2 * slice_y);
dest_rc = pp::Rect(
0, slice_y, slice_x, ctrl_background_.size().height() - 2 * slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, true);
// Copy rect 6
src_rc.set_x(background_.size().width() - slice_x);
dest_rc.set_x(ctrl_background_.size().width() - slice_x);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, true);
// Stretch rect 5
src_rc = pp::Rect(slice_x,
slice_y,
background_.size().width() - 2 * slice_x,
background_.size().height() - 2 * slice_y);
dest_rc = pp::Rect(slice_x,
slice_y,
ctrl_background_.size().width() - 2 * slice_x,
ctrl_background_.size().height() - 2 * slice_y);
CopyImage(background_, src_rc, &ctrl_background_, dest_rc, true);
}
} // namespace chrome_pdf

72
pdf/progress_control.h Normal file

@ -0,0 +1,72 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PROGRESS_CONTROL_H_
#define PDF_PROGRESS_CONTROL_H_
#include <string>
#include <vector>
#include "pdf/control.h"
#include "pdf/fading_control.h"
#include "ppapi/cpp/image_data.h"
namespace chrome_pdf {
class ProgressControl : public FadingControl {
public:
static const double kCompleted;
enum ProgressEventIds {
EVENT_ID_PROGRESS_COMPLETED,
};
ProgressControl();
virtual ~ProgressControl();
virtual bool CreateProgressControl(uint32 id,
bool visible,
Control::Owner* delegate,
double progress,
float device_scale,
const std::vector<pp::ImageData>& images,
const pp::ImageData& background,
const std::string& text);
void Reconfigure(const pp::ImageData& background,
const std::vector<pp::ImageData>& images,
float device_scale);
static void CalculateLayout(pp::Instance* instance,
const std::vector<pp::ImageData>& images,
const pp::ImageData& background,
const std::string& text,
float device_scale,
pp::Size* ctrl_size,
pp::Rect* image_rc,
pp::Rect* text_rc);
// Control interface.
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc);
// ProgressControl interface
// Set progress indicator in percents from 0% to 100%.
virtual void SetProgress(double progress);
private:
void PrepareBackground();
void AdjustBackground();
size_t GetImageIngex() const;
double progress_;
float device_scale_;
std::vector<pp::ImageData> images_;
pp::ImageData background_;
pp::ImageData ctrl_background_;
std::string text_;
pp::Rect image_rc_;
pp::Rect text_rc_;
};
} // namespace chrome_pdf
#endif // PDF_PROGRESS_CONTROL_H_

14
pdf/resource.h Normal file

@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by pdf.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

49
pdf/resource_consts.h Normal file

@ -0,0 +1,49 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_RESOURCE_RESOURCE_CONSTS_H_
#define PDF_RESOURCE_RESOURCE_CONSTS_H_
#include "base/basictypes.h"
namespace chrome_pdf {
const int kDragTimerMs = 50;
const double kMinZoom = 0.1;
const double kMaxZoom = 10.0;
const double kZoomStep = 1.2;
const uint32 kFadingTimeoutMs = 50;
const uint32 kToolbarId = 10;
const uint32 kThumbnailsId = 11;
const uint32 kProgressBarId = 12;
const uint32 kPageIndicatorId = 13;
const uint32 kFitToPageButtonId = 100;
const uint32 kFitToWidthButtonId = 101;
const uint32 kZoomOutButtonId = 102;
const uint32 kZoomInButtonId = 103;
const uint32 kSaveButtonId = 104;
const uint32 kPrintButtonId = 105;
const uint32 kAutoScrollId = 200;
// fading_rect.left = button_rect.left - kToolbarFadingOffsetLeft
const int32 kToolbarFadingOffsetLeft = 40;
// fading_rect.top = button_rect.top - kToolbarFadingOffsetTop
const int32 kToolbarFadingOffsetTop = 40;
// fading_rect.right = button_rect.right + kToolbarFadingOffsetRight
const int32 kToolbarFadingOffsetRight = 10;
// fading_rect.bottom = button_rect.bottom + kToolbarFadingOffsetBottom
const int32 kToolbarFadingOffsetBottom = 8;
const int32 kProgressOffsetLeft = 8;
const int32 kProgressOffsetBottom = 8;
// Width of the thumbnails control.
const int32 kThumbnailsWidth = 196;
} // namespace chrome_pdf
#endif // PDF_RESOURCE_RESOURCE_CONSTS_H_

301
pdf/thumbnail_control.cc Normal file

@ -0,0 +1,301 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/thumbnail_control.h"
#include <algorithm>
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "pdf/draw_utils.h"
#include "pdf/number_image_generator.h"
namespace chrome_pdf {
const int kLeftBorderSize = 52;
const int kBorderSize = 12;
const int kHighlightBorderSize = 2;
const uint32 kLeftColor = 0x003F537B;
const uint32 kRightColor = 0x990D1626;
const uint32 kTopHighlightColor = 0xFF426DC9;
const uint32 kBottomHighlightColor = 0xFF6391DE;
const uint32 kThumbnailBackgroundColor = 0xFF000000;
const uint32 kSlidingTimeoutMs = 50;
const int32 kSlidingShift = 50;
const double kNonSelectedThumbnailAlpha = 0.91;
ThumbnailControl::ThumbnailControl()
: engine_(NULL), sliding_width_(0), sliding_shift_(kSlidingShift),
sliding_timeout_(kSlidingTimeoutMs), sliding_timer_id_(0) {
}
ThumbnailControl::~ThumbnailControl() {
ClearCache();
}
bool ThumbnailControl::CreateThumbnailControl(
uint32 id, const pp::Rect& rc,
bool visible, Owner* owner, PDFEngine* engine,
NumberImageGenerator* number_image_generator) {
engine_ = engine;
number_image_generator_ = number_image_generator;
sliding_width_ = rc.width();
return Control::Create(id, rc, visible, owner);
}
void ThumbnailControl::SetPosition(int position, int total, bool invalidate) {
visible_rect_ = pp::Rect();
visible_pages_.clear();
if (rect().width() < kLeftBorderSize + kBorderSize) {
return; // control is too narrow to show thumbnails.
}
int num_pages = engine_->GetNumberOfPages();
int max_doc_width = 0, total_doc_height = 0;
std::vector<pp::Rect> page_sizes(num_pages);
for (int i = 0; i < num_pages; ++i) {
page_sizes[i] = engine_->GetPageRect(i);
max_doc_width = std::max(max_doc_width, page_sizes[i].width());
total_doc_height += page_sizes[i].height();
}
if (!max_doc_width)
return;
int max_thumbnail_width = rect().width() - kLeftBorderSize - kBorderSize;
double thumbnail_ratio =
max_thumbnail_width / static_cast<double>(max_doc_width);
int total_thumbnail_height = 0;
for (int i = 0; i < num_pages; ++i) {
total_thumbnail_height += kBorderSize;
int thumbnail_width =
static_cast<int>(page_sizes[i].width() * thumbnail_ratio);
int thumbnail_height =
static_cast<int>(page_sizes[i].height() * thumbnail_ratio);
int x = (max_thumbnail_width - thumbnail_width) / 2;
page_sizes[i] =
pp::Rect(x, total_thumbnail_height, thumbnail_width, thumbnail_height);
total_thumbnail_height += thumbnail_height;
}
total_thumbnail_height += kBorderSize;
int visible_y = 0;
if (total > 0) {
double range = total_thumbnail_height - rect().height();
if (range < 0)
range = 0;
visible_y = static_cast<int>(range * position / total);
}
visible_rect_ = pp::Rect(0, visible_y, max_thumbnail_width, rect().height());
for (int i = 0; i < num_pages; ++i) {
if (page_sizes[i].Intersects(visible_rect_)) {
PageInfo page_info;
page_info.index = i;
page_info.rect = page_sizes[i];
page_info.rect.Offset(kLeftBorderSize, -visible_rect_.y());
visible_pages_.push_back(page_info);
}
}
if (invalidate)
owner()->Invalidate(id(), rect());
}
void ThumbnailControl::Show(bool visible, bool invalidate) {
if (!visible || invalidate)
ClearCache();
sliding_width_ = rect().width();
Control::Show(visible, invalidate);
}
void ThumbnailControl::SlideIn() {
if (visible())
return;
Show(true, false);
sliding_width_ = 0;
sliding_shift_ = kSlidingShift;
sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_);
owner()->Invalidate(id(), rect());
}
void ThumbnailControl::SlideOut() {
if (!visible())
return;
sliding_shift_ = -kSlidingShift;
sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_);
}
void ThumbnailControl::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
if (!visible())
return;
pp::Rect control_rc(rect());
control_rc.Offset(control_rc.width() - sliding_width_, 0);
control_rc.set_width(sliding_width_);
pp::Rect draw_rc = rc.Intersect(control_rc);
if (draw_rc.IsEmpty())
return;
pp::Rect gradient_rc(control_rc.x(), draw_rc.y(),
control_rc.width(), draw_rc.height());
GradientFill(owner()->GetInstance(),
image_data,
draw_rc,
gradient_rc,
kLeftColor,
kRightColor,
true,
transparency());
int selected_page = engine_->GetMostVisiblePage();
for (size_t i = 0; i < visible_pages_.size(); ++i) {
pp::Rect page_rc = visible_pages_[i].rect;
page_rc.Offset(control_rc.point());
if (visible_pages_[i].index == selected_page) {
pp::Rect highlight_rc = page_rc;
highlight_rc.Inset(-kHighlightBorderSize, -kHighlightBorderSize);
GradientFill(owner()->GetInstance(),
image_data,
draw_rc,
highlight_rc,
kTopHighlightColor,
kBottomHighlightColor,
false,
transparency());
}
pp::Rect draw_page_rc = page_rc.Intersect(draw_rc);
if (draw_page_rc.IsEmpty())
continue;
// First search page image in the cache.
pp::ImageData* thumbnail = NULL;
std::map<int, pp::ImageData*>::iterator it =
image_cache_.find(visible_pages_[i].index);
if (it != image_cache_.end()) {
if (it->second->size() == page_rc.size())
thumbnail = image_cache_[visible_pages_[i].index];
else
image_cache_.erase(it);
}
// If page is not found in the cache, create new one.
if (thumbnail == NULL) {
thumbnail = new pp::ImageData(owner()->GetInstance(),
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
page_rc.size(),
false);
engine_->PaintThumbnail(thumbnail, visible_pages_[i].index);
pp::ImageData page_number;
number_image_generator_->GenerateImage(
visible_pages_[i].index + 1, &page_number);
pp::Point origin(
(thumbnail->size().width() - page_number.size().width()) / 2,
(thumbnail->size().height() - page_number.size().height()) / 2);
if (origin.x() > 0 && origin.y() > 0) {
AlphaBlend(page_number, pp::Rect(pp::Point(), page_number.size()),
thumbnail, origin, kOpaqueAlpha);
}
image_cache_[visible_pages_[i].index] = thumbnail;
}
uint8 alpha = transparency();
if (visible_pages_[i].index != selected_page)
alpha = static_cast<uint8>(alpha * kNonSelectedThumbnailAlpha);
FillRect(image_data, draw_page_rc, kThumbnailBackgroundColor);
draw_page_rc.Offset(-page_rc.x(), -page_rc.y());
AlphaBlend(*thumbnail, draw_page_rc, image_data,
draw_page_rc.point() + page_rc.point(), alpha);
}
}
bool ThumbnailControl::HandleEvent(const pp::InputEvent& event) {
if (!visible())
return false;
pp::MouseInputEvent mouse_event(event);
if (mouse_event.is_null())
return false;
pp::Point pt = mouse_event.GetPosition();
if (!rect().Contains(pt))
return false;
int over_page = -1;
for (size_t i = 0; i < visible_pages_.size(); ++i) {
pp::Rect page_rc = visible_pages_[i].rect;
page_rc.Offset(rect().point());
if (page_rc.Contains(pt)) {
over_page = i;
break;
}
}
bool handled = false;
switch (event.GetType()) {
case PP_INPUTEVENT_TYPE_MOUSEMOVE:
owner()->SetCursor(id(),
over_page == -1 ? PP_CURSORTYPE_POINTER : PP_CURSORTYPE_HAND);
break;
case PP_INPUTEVENT_TYPE_MOUSEDOWN:
if (over_page != -1) {
owner()->Invalidate(id(), rect());
owner()->OnEvent(id(), EVENT_ID_THUMBNAIL_SELECTED,
&visible_pages_[over_page].index);
}
handled = true;
break;
default:
break;
}
return handled;
}
void ThumbnailControl::OnTimerFired(uint32 timer_id) {
if (timer_id == sliding_timer_id_) {
sliding_width_ += sliding_shift_;
if (sliding_width_ <= 0) {
// We completely slided out. Make control invisible now.
Show(false, false);
} else if (sliding_width_ >= rect().width()) {
// We completely slided in. Make sliding width to full control width.
sliding_width_ = rect().width();
} else {
// We have not completed sliding yet. Keep sliding.
sliding_timer_id_ = owner()->ScheduleTimer(id(), sliding_timeout_);
}
owner()->Invalidate(id(), rect());
}
}
void ThumbnailControl::ResetEngine(PDFEngine* engine) {
engine_ = engine;
ClearCache();
}
void ThumbnailControl::ClearCache() {
std::map<int, pp::ImageData*>::iterator it;
for (it = image_cache_.begin(); it != image_cache_.end(); ++it) {
delete it->second;
}
image_cache_.clear();
}
} // namespace chrome_pdf

67
pdf/thumbnail_control.h Normal file

@ -0,0 +1,67 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_THUMBNAIL_CONTROL_H_
#define PDF_THUMBNAIL_CONTROL_H_
#include <map>
#include <vector>
#include "pdf/control.h"
#include "pdf/pdf_engine.h"
#include "ppapi/cpp/input_event.h"
namespace chrome_pdf {
class NumberImageGenerator;
class ThumbnailControl : public Control {
public:
enum ThumbnailEventIds {
EVENT_ID_THUMBNAIL_SELECTED = 100,
};
explicit ThumbnailControl();
virtual ~ThumbnailControl();
// Sets current position of the thumnail control.
void SetPosition(int position, int total, bool invalidate);
void SlideIn();
void SlideOut();
virtual bool CreateThumbnailControl(
uint32 id, const pp::Rect& rc,
bool visible, Owner* owner, PDFEngine* engine,
NumberImageGenerator* number_image_generator);
// Control interface.
virtual void Show(bool visible, bool invalidate);
virtual void Paint(pp::ImageData* image_data, const pp::Rect& rc);
virtual bool HandleEvent(const pp::InputEvent& event);
virtual void OnTimerFired(uint32 timer_id);
virtual void ResetEngine(PDFEngine* engine);
private:
void ClearCache();
struct PageInfo {
int index;
pp::Rect rect;
};
PDFEngine* engine_;
pp::Rect visible_rect_;
std::vector<PageInfo> visible_pages_;
std::map<int, pp::ImageData*> image_cache_;
int sliding_width_;
int sliding_shift_;
int sliding_timeout_;
uint32 sliding_timer_id_;
NumberImageGenerator* number_image_generator_;
};
} // namespace chrome_pdf
#endif // PDF_THUMBNAIL_CONTROL_H_