Skip to content

Commit 2ca0f79

Browse files
committed
Working code for handling PDFs.
PluginLoader overrides the PluginLoader in webodf with an extra entry for PDF files, and that's all. During building, the built viewer/ directory is copied from webodf to Viewer.js's build tree, and PluginLoader is overwritten with Viewer.js's copy.
1 parent 970772a commit 2ca0f79

5 files changed

Lines changed: 871 additions & 3 deletions

File tree

CMakeLists.txt

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,39 @@ else ( IS_DIRECTORY $ENV{VIEWERJS_DOWNLOAD_DIR} )
5757
endif ( IS_DIRECTORY $ENV{VIEWERJS_DOWNLOAD_DIR} )
5858
MESSAGE ( STATUS "external downloads will be stored/expected in: ${EXTERNALS_DOWNLOAD_DIR}" )
5959

60+
SET ( VIEWER_BUILD_DIR ${CMAKE_BINARY_DIR}/viewer )
61+
FILE ( MAKE_DIRECTORY ${VIEWER_BUILD_DIR})
62+
6063
ExternalProject_Add(
6164
WebODF
6265
GIT_REPOSITORY git@gitorious.org:webodf/webodf.git
63-
UPDATE_COMMAND ""
64-
INSTALL_COMMAND ""
65-
ALWAYS 0
66+
UPDATE_COMMAND git pull origin master
67+
BUILD_COMMAND make viewerbuilddir-target
68+
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/WebODF-Prefix/src/WebODF-build/viewer/ ${VIEWER_BUILD_DIR}
6669
)
6770

71+
ExternalProject_Add(
72+
PDFjs
73+
GIT_REPOSITORY git@github.com:mozilla/pdf.js.git
74+
UPDATE_COMMAND git pull
75+
CONFIGURE_COMMAND ""
76+
BUILD_COMMAND node ${CMAKE_BINARY_DIR}/PDFjs-Prefix/src/PDFjs/make.js generic
77+
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/PDFjs-Prefix/src/PDFjs/build/generic/build/pdf.js ${VIEWER_BUILD_DIR}/pdf.js
78+
)
79+
80+
add_custom_command(
81+
OUTPUT ${VIEWER_BUILD_DIR}/PDFViewerPlugin.js
82+
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/PluginLoader.js ${VIEWER_BUILD_DIR}/PluginLoader.js
83+
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/PDFViewerPlugin.js ${VIEWER_BUILD_DIR}/PDFViewerPlugin.js
84+
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/TextLayerBuilder.js ${VIEWER_BUILD_DIR}/TextLayerBuilder.js
85+
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/PDFViewerPlugin.css ${VIEWER_BUILD_DIR}/PDFViewerPlugin.css
86+
COMMAND ${CMAKE_COMMAND} -E echo ${VIEWER_BUILD_DIR}
87+
)
88+
89+
90+
add_custom_target(Viewer ALL
91+
DEPENDS
92+
${VIEWER_BUILD_DIR}/PDFViewerPlugin.js
93+
WebODF
94+
PDFjs
95+
)

PDFViewerPlugin.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.page {
2+
margin: 7px auto 7px auto;
3+
position: relative;
4+
overflow: visible;
5+
background-clip: content-box;
6+
background-color: white;
7+
8+
box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.75);
9+
-webkit-box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.75);
10+
-moz-box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.75);
11+
-ms-box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.75);
12+
-o-box-shadow: 0px 0px 7px rgba(0, 0, 0, 0.75);
13+
}
14+
15+
.textLayer {
16+
position: absolute;
17+
left: 0;
18+
top: 0;
19+
right: 0;
20+
bottom: 0;
21+
color: #000;
22+
font-family: sans-serif;
23+
overflow: hidden;
24+
}
25+
26+
.textLayer > div {
27+
color: transparent;
28+
position: absolute;
29+
line-height: 1;
30+
white-space: pre;
31+
cursor: text;
32+
overflow: hidden;
33+
}
34+
35+
::selection { background:rgba(0,0,255,0.3); }
36+

PDFViewerPlugin.js

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/**
2+
* @license
3+
* Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
4+
*
5+
* @licstart
6+
* The JavaScript code in this page is free software: you can redistribute it
7+
* and/or modify it under the terms of the GNU Affero General Public License
8+
* (GNU AGPL) as published by the Free Software Foundation, either version 3 of
9+
* the License, or (at your option) any later version. The code is distributed
10+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU AGPL for more details.
12+
*
13+
* As additional permission under GNU AGPL version 3 section 7, you
14+
* may distribute non-source (e.g., minimized or compacted) forms of
15+
* that code without the copy of the GNU GPL normally required by
16+
* section 4, provided you include this license notice and a URL
17+
* through which recipients can access the Corresponding Source.
18+
*
19+
* As a special exception to the AGPL, any HTML file which merely makes function
20+
* calls to this code, and for that purpose includes it by reference shall be
21+
* deemed a separate work for copyright law purposes. In addition, the copyright
22+
* holders of this code give you permission to combine this code with free
23+
* software libraries that are released under the GNU LGPL. You may copy and
24+
* distribute such a system following the terms of the GNU AGPL for this code
25+
* and the LGPL for the libraries. If you modify this code, you may extend this
26+
* exception to your version of the code, but you are not obligated to do so.
27+
* If you do not wish to do so, delete this exception statement from your
28+
* version.
29+
*
30+
* This license applies to this entire compilation.
31+
* @licend
32+
* @source: http://www.webodf.org/
33+
* @source: http://gitorious.org/webodf/webodf/
34+
*/
35+
36+
/*global document, PDFJS, console, TextLayerBuilder*/
37+
38+
39+
function PDFViewerPlugin() {
40+
"use strict";
41+
42+
function init(callback) {
43+
var pdfLib, textLayerLib, pluginCSS;
44+
45+
pdfLib = document.createElement('script');
46+
pdfLib.async = false;
47+
pdfLib.src = './pdf.js';
48+
pdfLib.type = 'text/javascript';
49+
pdfLib.onload = function () {
50+
textLayerLib = document.createElement('script');
51+
textLayerLib.async = false;
52+
textLayerLib.src = './TextLayerBuilder.js';
53+
textLayerLib.type = 'text/javascript';
54+
textLayerLib.onload = callback;
55+
document.getElementsByTagName('head')[0].appendChild(textLayerLib);
56+
};
57+
document.getElementsByTagName('head')[0].appendChild(pdfLib);
58+
59+
pluginCSS = document.createElement('link');
60+
pluginCSS.setAttribute("rel", "stylesheet");
61+
pluginCSS.setAttribute("type", "text/css");
62+
pluginCSS.setAttribute("href", "./PDFViewerPlugin.css");
63+
document.head.appendChild(pluginCSS);
64+
}
65+
66+
var self = this,
67+
pages = [],
68+
domPages = [],
69+
pageText = [],
70+
renderingStates = [],
71+
RENDERING = {
72+
BLANK: 0,
73+
RUNNING: 1,
74+
FINISHED: 2
75+
},
76+
startedTextExtraction = false,
77+
container = null,
78+
initialized = false,
79+
pdfDocument = null,
80+
pageViewScroll = null,
81+
isPresentationMode = false,
82+
scale = 1,
83+
currentPage = 1,
84+
pageWidth,
85+
pageHeight,
86+
createdPageCount = 0;
87+
88+
function isScrolledIntoView(elem) {
89+
var docViewTop = container.scrollTop,
90+
docViewBottom = docViewTop + container.clientHeight,
91+
elemTop = elem.offsetTop,
92+
elemBottom = elemTop + elem.clientHeight;
93+
94+
// Is in view if either the top or the bottom of the page is between the
95+
// document viewport bounds,
96+
// or if the top is above the viewport and the bottom is below it.
97+
return (elemTop >= docViewTop && elemTop < docViewBottom)
98+
|| (elemBottom >= docViewTop && elemBottom < docViewBottom)
99+
|| (elemTop < docViewTop && elemBottom >= docViewBottom);
100+
}
101+
102+
function getDomPage(page) {
103+
return domPages[page.pageInfo.pageIndex];
104+
}
105+
function getPageText(page) {
106+
return pageText[page.pageInfo.pageIndex];
107+
}
108+
function getRenderingStatus(page) {
109+
return renderingStates[page.pageInfo.pageIndex];
110+
}
111+
function setRenderingStatus(page, renderStatus) {
112+
renderingStates[page.pageInfo.pageIndex] = renderStatus;
113+
}
114+
115+
function updatePageDimensions(page, width, height) {
116+
var domPage = getDomPage(page),
117+
canvas = domPage.getElementsByTagName('canvas')[0],
118+
textLayer = domPage.getElementsByTagName('div')[0];
119+
120+
domPage.style.width = width;
121+
domPage.style.height = height;
122+
123+
canvas.width = width;
124+
canvas.height = height;
125+
126+
textLayer.style.width = width;
127+
textLayer.style.height = height;
128+
129+
// Once the page dimension is updated, the rendering state is blank.
130+
setRenderingStatus(page, RENDERING.BLANK);
131+
}
132+
133+
function renderPage(page) {
134+
var domPage = getDomPage(page),
135+
textLayer = getPageText(page),
136+
canvas = domPage.getElementsByTagName('canvas')[0];
137+
138+
if (getRenderingStatus(page) === RENDERING.BLANK) {
139+
setRenderingStatus(page, RENDERING.RUNNING);
140+
page.render({
141+
canvasContext: canvas.getContext('2d'),
142+
textLayer: textLayer,
143+
viewport: page.getViewport(scale)
144+
}).then(function () {
145+
setRenderingStatus(page, RENDERING.FINISHED);
146+
});
147+
}
148+
}
149+
150+
function createPage(page) {
151+
var pageNumber,
152+
textLayerDiv,
153+
textLayer,
154+
canvas,
155+
domPage,
156+
viewport;
157+
158+
pageNumber = page.pageInfo.pageIndex + 1;
159+
160+
viewport = page.getViewport(scale);
161+
162+
domPage = document.createElement('div');
163+
domPage.id = 'pageContainer' + pageNumber;
164+
domPage.className = 'page';
165+
166+
canvas = document.createElement('canvas');
167+
canvas.id = 'canvas' + pageNumber;
168+
169+
textLayerDiv = document.createElement('div');
170+
textLayerDiv.className = 'textLayer';
171+
textLayerDiv.id = 'textLayer' + pageNumber;
172+
173+
container.appendChild(domPage);
174+
domPage.appendChild(canvas);
175+
domPage.appendChild(textLayerDiv);
176+
177+
pages.push(page);
178+
domPages.push(domPage);
179+
renderingStates.push(RENDERING.BLANK);
180+
181+
updatePageDimensions(page, viewport.width, viewport.height);
182+
pageWidth = viewport.width;
183+
pageHeight = viewport.height;
184+
185+
textLayer = new TextLayerBuilder({
186+
textLayerDiv: textLayerDiv,
187+
pageIndex: pageNumber - 1
188+
});
189+
page.getTextContent().then(function (textContent) {
190+
textLayer.setTextContent(textContent);
191+
});
192+
pageText.push(textLayer);
193+
194+
createdPageCount += 1;
195+
if (createdPageCount === (pdfDocument.numPages)) {
196+
self.onLoad();
197+
}
198+
}
199+
200+
this.initialize = function (viewContainer, location) {
201+
var self = this,
202+
i,
203+
pluginCSS;
204+
205+
init(function () {
206+
PDFJS.disableWorker = true;
207+
PDFJS.getDocument(location).then(function loadPDF(doc) {
208+
pdfDocument = doc;
209+
container = viewContainer;
210+
211+
for (i = 0; i < pdfDocument.numPages; i += 1) {
212+
pdfDocument.getPage(i + 1).then(createPage);
213+
}
214+
215+
initialized = true;
216+
});
217+
});
218+
};
219+
220+
this.isSlideshow = function () {
221+
return false;
222+
};
223+
224+
this.onLoad = function () {};
225+
226+
this.getPages = function () {
227+
return domPages;
228+
};
229+
230+
this.getWidth = function () {
231+
return pageWidth;
232+
};
233+
234+
this.getHeight = function () {
235+
return pageHeight;
236+
};
237+
238+
this.fitToWidth = function (width) {
239+
var zoomLevel;
240+
241+
if (self.getWidth() === width) {
242+
return;
243+
}
244+
zoomLevel = width / pageWidth;
245+
self.setZoomLevel(zoomLevel);
246+
};
247+
248+
this.fitToHeight = function (height) {
249+
var zoomLevel;
250+
251+
if (self.getHeight() === height) {
252+
return;
253+
}
254+
zoomLevel = height / pageHeight;
255+
self.setZoomLevel(zoomLevel);
256+
};
257+
258+
this.fitToContainingElement = function (width, height) {
259+
var zoomLevel = width / pageWidth;
260+
if (height / pageHeight < zoomLevel) {
261+
zoomLevel = height / pageHeight;
262+
}
263+
self.setZoomLevel(zoomLevel);
264+
};
265+
266+
this.fitSmart = function (width, height) {
267+
var zoomLevel = width / pageWidth;
268+
if (height && (height / pageHeight) < zoomLevel) {
269+
zoomLevel = height / pageHeight;
270+
}
271+
zoomLevel = Math.min(1.0, zoomLevel);
272+
self.setZoomLevel(zoomLevel);
273+
};
274+
275+
this.setZoomLevel = function (zoomLevel) {
276+
var i;
277+
278+
if (scale !== zoomLevel) {
279+
scale = zoomLevel;
280+
281+
for (i = 0; i < pages.length; i += 1) {
282+
updatePageDimensions(pages[i], pageWidth * scale, pageHeight * scale);
283+
}
284+
}
285+
};
286+
287+
this.getZoomLevel = function () {
288+
return scale;
289+
};
290+
291+
this.onScroll = function () {
292+
var i;
293+
294+
for (i = 0; i < domPages.length; i += 1) {
295+
if (isScrolledIntoView(domPages[i])) {
296+
if (getRenderingStatus(pages[i]) === RENDERING.BLANK) {
297+
renderPage(pages[i]);
298+
}
299+
}
300+
}
301+
};
302+
303+
this.getPageInView = function () {
304+
var i;
305+
for (i = 0; i < domPages.length; i += 1) {
306+
if (isScrolledIntoView(domPages[i])) {
307+
return i + 1;
308+
}
309+
}
310+
};
311+
312+
this.showPage = function (n) {
313+
domPages[n - 1].scrollIntoView();
314+
};
315+
}

0 commit comments

Comments
 (0)