Search code examples
cordovauwpvisual-studio-cordovaviewerpdf.js

Windows Cordova App: An app can’t load remote web content in the local context


I have a UWP cordova app, which uses the PDFJS to render the pdf files. It's loading the embedded fonts as data-uri, but I am getting the error An app can’t load remote web content in the local context. along with the warning Warning: Load test font never loaded.. What I am trying to do is like this, but within a UWP app: https://mozilla.github.io/pdf.js/web/viewer.html

This is the code where it loads the fonts (found in pdf.js around line 7390):

    data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, (0, _util.string32)(checksum));
    var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
    var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' + url + '}';

One such scenerio: @font-face { font-family:"g_d0_f9"; src:url(data:font/opentype;base64,T1RUTwAJAIAAAwAQQ0ZGIHp+hQ4AAACcAAAEQE9TLzJEe6zGAAAE3AAAAGBjbWFwlcEWgAAABTwAAAK0aGVhZKsnUBMAAAfwAAAANmhoZWEDxgIHAAAIKAAAACRobXR4AAAAAAAACEwAAAAsbWF4cAALUAAAAAh4AAAABm5hbWWVrNe7AAAIgAAAAnZwb3N0AAMAAAAACvgAAAAgAQAEAgABAQEhS0VKRVBSK1N3aXNzNzIxQlQtTGlnaHRDb25kZW5zZWQAAQEBK/gbAfgWBPs7+4D6fPpXBR0AAADKDx0AAADXER0AAAAaHQAABCUS+BwMFQACAQFdakNvcHlyaWdodCAxOTkwIGFzIGFuIHVucHVibGlzaGVkIHdvcmsgYnkgQml0c3RyZWFtIEluYy4gIEFsbCByaWdodHMgcmVzZXJ2ZWQuICBDb25maWRlbnRpYWwuL0ZTVHlwZSAwIGRlZgAAAAEAEQYAJQAAMAAANAAACwIAAQAEAGEAjQDpAVYBhgHYAjkCcQK/AzT76A58wvkgwwG8y/eFzAO8+AMV+xyTLaVXHkmsvmnOG86+rc2rH6W/lOn3HBr3HIHocr8ezWtYrUgbSFhpSWofcVeDLvscGsuKFfdvo/bs7KIg+2/7b3QgKipz9fdwHg6Ln/iosvcPnwH3dMgD93QWyPlyXAaAJltl+wOHCGUHipmYi5gbs7GOkbEfDovI+QvDEr7OU8T3fckT6L4W+AHI+74GjNPEx+biuri8s6fLCJqtk7S5GvcRRNT7AB4TWCJHP/sWH4DEB/cAjbPA2xvOt1g1+wFOUTs7H1lZXmBxXHFcf1SKSQgOfcT30MH3rcISvcdgx/dox2DLE5K991kV+xuM0D/3ARv3CtTd9xvvZcg5px8TbMuqrsffGvcDR9ImKE5F+xKIHseOBuSzvMzNtF06IVdb+wgeh1QGjJa)

Any way I can get it load the files?

Folder structure:

  • index.html
  • main.js
  • pdf-js/
    • cmaps/
    • images/
    • locale/
    • compatibility.js
    • l10n.js
    • pdf.js
    • pdf.worker.js
    • viewer.css
    • viewer.js

Index.html (The markup contained here is extracted from viewer.html)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link href="pdf-js/viewer.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="js/compatibility.js"></script>
  <link rel="resource" type="application/l10n" href="pdf-js/locale/locale.properties">
  <script type="text/javascript" src="pdf-js/l10n.js"></script>
  <script type="text/javascript" src="pdf-js/pdf.js"></script>
  <script type="text/javascript" src="pdf-js/pdf.worker.js"></script>
  <script type="text/javascript" src="pdf-js/viewer.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>
<body>
  <div id="pdf-viewer">
    <div id="outerContainer">
        <div id="sidebarContainer">
            <div id="toolbarSidebar">
                <div class="splitToolbarButton toggled">
                    <button id="viewThumbnail" class="toolbarButton group toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs">
                        <span data-l10n-id="thumbs_label">Thumbnails</span>
                    </button>
                    <button id="viewOutline" class="toolbarButton group" title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3" data-l10n-id="document_outline">
                        <span data-l10n-id="document_outline_label">Document Outline</span>
                    </button>
                    <button id="viewAttachments" class="toolbarButton group" title="Show Attachments" tabindex="4" data-l10n-id="attachments">
                        <span data-l10n-id="attachments_label">Attachments</span>
                    </button>
                </div>
            </div>
            <div id="sidebarContent">
                <div id="thumbnailView">
                </div>
                <div id="outlineView" class="hidden">
                </div>
                <div id="attachmentsView" class="hidden">
                </div>
            </div>
        </div>  <!-- sidebarContainer -->

        <div id="mainContainer">
            <div class="findbar hidden doorHanger hiddenSmallView" id="findbar">
                <label for="findInput" class="toolbarLabel" data-l10n-id="find_label">Find:</label>
                <input id="findInput" class="toolbarField" tabindex="91">
                <div class="splitToolbarButton">
                    <button class="toolbarButton findPrevious" title="" id="findPrevious" tabindex="92" data-l10n-id="find_previous">
                        <span data-l10n-id="find_previous_label">Previous</span>
                    </button>
                    <div class="splitToolbarButtonSeparator"></div>
                    <button class="toolbarButton findNext" title="" id="findNext" tabindex="93" data-l10n-id="find_next">
                        <span data-l10n-id="find_next_label">Next</span>
                    </button>
                </div>
                <input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
                <label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight all</label>
                <input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
                <label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match case</label>
                <span id="findResultsCount" class="toolbarLabel hidden"></span>
                <span id="findMsg" class="toolbarLabel"></span>
            </div>  <!-- findbar -->

            <div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
                <div id="secondaryToolbarButtonContainer">
                    <button id="secondaryPresentationMode" class="secondaryToolbarButton presentationMode visibleLargeView hidden" title="Switch to Presentation Mode" tabindex="51" data-l10n-id="presentation_mode">
                        <span data-l10n-id="presentation_mode_label">Presentation Mode</span>
                    </button>

                    <button id="secondaryOpenFile" class="secondaryToolbarButton openFile visibleLargeView hidden" title="Open File" tabindex="52" data-l10n-id="open_file">
                        <span data-l10n-id="open_file_label">Open</span>
                    </button>

                    <button id="secondaryPrint" class="secondaryToolbarButton print visibleMediumView" title="Print" tabindex="53" data-l10n-id="print">
                        <span data-l10n-id="print_label">Print</span>
                    </button>

                    <button id="secondaryDownload" class="secondaryToolbarButton download visibleMediumView hidden" title="Download" tabindex="54" data-l10n-id="download">
                        <span data-l10n-id="download_label">Download</span>
                    </button>

                    <a href="#" id="secondaryViewBookmark" class="secondaryToolbarButton bookmark visibleSmallView hidden" title="Current view (copy or open in new window)" tabindex="55" data-l10n-id="bookmark">
                        <span data-l10n-id="bookmark_label">Current View</span>
                    </a>

                    <div class="horizontalToolbarSeparator visibleLargeView"></div>

                    <button id="firstPage" class="secondaryToolbarButton firstPage" title="Go to First Page" tabindex="56" data-l10n-id="first_page">
                        <span data-l10n-id="first_page_label">Go to First Page</span>
                    </button>
                    <button id="lastPage" class="secondaryToolbarButton lastPage" title="Go to Last Page" tabindex="57" data-l10n-id="last_page">
                        <span data-l10n-id="last_page_label">Go to Last Page</span>
                    </button>

                    <div class="horizontalToolbarSeparator"></div>

                    <button id="pageRotateCw" class="secondaryToolbarButton rotateCw" title="Rotate Clockwise" tabindex="58" data-l10n-id="page_rotate_cw">
                        <span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
                    </button>
                    <button id="pageRotateCcw" class="secondaryToolbarButton rotateCcw" title="Rotate Counterclockwise" tabindex="59" data-l10n-id="page_rotate_ccw">
                        <span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwise</span>
                    </button>

                    <div class="horizontalToolbarSeparator"></div>

                    <button id="toggleHandTool" class="secondaryToolbarButton handTool" title="Enable hand tool" tabindex="60" data-l10n-id="hand_tool_enable">
                        <span data-l10n-id="hand_tool_enable_label">Enable hand tool</span>
                    </button>

                    <div class="horizontalToolbarSeparator"></div>

                    <button id="documentProperties" class="secondaryToolbarButton documentProperties" title="Document Properties…" tabindex="61" data-l10n-id="document_properties">
                        <span data-l10n-id="document_properties_label">Document Properties…</span>
                    </button>
                </div>
            </div>  <!-- secondaryToolbar -->

            <div class="toolbar">
                <div id="toolbarContainer">
                    <div id="toolbarViewer">
                        <div id="toolbarViewerLeft">
                            <button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="11" data-l10n-id="toggle_sidebar">
                                <span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
                            </button>
                            <div class="toolbarButtonSpacer"></div>
                            <button id="viewFind" class="toolbarButton group hiddenSmallView" title="Find in Document" tabindex="12" data-l10n-id="findbar">
                                <span data-l10n-id="findbar_label">Find</span>
                            </button>
                            <div class="splitToolbarButton">
                                <button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="13" data-l10n-id="previous">
                                    <span data-l10n-id="previous_label">Previous</span>
                                </button>
                                <div class="splitToolbarButtonSeparator"></div>
                                <button class="toolbarButton pageDown" title="Next Page" id="next" tabindex="14" data-l10n-id="next">
                                    <span data-l10n-id="next_label">Next</span>
                                </button>
                            </div>
                            <input type="number" id="pageNumber" class="toolbarField pageNumber" title="Page" value="1" size="4" min="1" tabindex="15" data-l10n-id="page">
                            <span id="numPages" class="toolbarLabel"></span>
                        </div>
                        <div id="toolbarViewerRight">
                            <button id="presentationMode" class="toolbarButton presentationMode hiddenLargeView hidden" title="Switch to Presentation Mode" tabindex="31" data-l10n-id="presentation_mode">
                                <span data-l10n-id="presentation_mode_label">Presentation Mode</span>
                            </button>

                            <button id="openFile" class="toolbarButton openFile hiddenLargeView hidden" title="Open File" tabindex="32" data-l10n-id="open_file">
                                <span data-l10n-id="open_file_label">Open</span>
                            </button>

                            <button id="print" class="toolbarButton print hiddenMediumView" title="Print" tabindex="33" data-l10n-id="print">
                                <span data-l10n-id="print_label">Print</span>
                            </button>

                            <button id="download" class="toolbarButton download hiddenMediumView hidden" title="Download" tabindex="34" data-l10n-id="download">
                                <span data-l10n-id="download_label">Download</span>
                            </button>
                            <a href="#" id="viewBookmark" class="toolbarButton bookmark hiddenSmallView hidden" title="Current view (copy or open in new window)" tabindex="35" data-l10n-id="bookmark">
                                <span data-l10n-id="bookmark_label">Current View</span>
                            </a>

                            <div class="verticalToolbarSeparator hiddenSmallView"></div>

                            <button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="36" data-l10n-id="tools">
                                <span data-l10n-id="tools_label">Tools</span>
                            </button>
                        </div>
                        <div id="toolbarViewerMiddle">
                            <div class="splitToolbarButton">
                                <button id="zoomOut" class="toolbarButton zoomOut" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
                                    <span data-l10n-id="zoom_out_label">Zoom Out</span>
                                </button>
                                <div class="splitToolbarButtonSeparator"></div>
                                <button id="zoomIn" class="toolbarButton zoomIn" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
                                    <span data-l10n-id="zoom_in_label">Zoom In</span>
                                </button>
                            </div>
                            <span id="scaleSelectContainer" class="dropdownToolbarButton">
                                <select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
                                    <option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
                                    <option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
                                    <option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>
                                    <option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Full Width</option>
                                    <option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"></option>
                                    <option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option>
                                    <option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option>
                                    <option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option>
                                    <option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option>
                                    <option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option>
                                    <option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option>
                                    <option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option>
                                    <option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option>
                                </select>
                            </span>
                        </div>
                    </div>
                    <div id="loadingBar">
                        <div class="progress">
                            <div class="glimmer">
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <menu type="context" id="viewerContextMenu">
                <menuitem id="contextFirstPage" label="First Page"
                          data-l10n-id="first_page"></menuitem>
                <menuitem id="contextLastPage" label="Last Page"
                          data-l10n-id="last_page"></menuitem>
                <menuitem id="contextPageRotateCw" label="Rotate Clockwise"
                          data-l10n-id="page_rotate_cw"></menuitem>
                <menuitem id="contextPageRotateCcw" label="Rotate Counter-Clockwise"
                          data-l10n-id="page_rotate_ccw"></menuitem>
            </menu>

            <div id="viewerContainer" tabindex="0">
                <div id="viewer" class="pdfViewer"></div>
            </div>

            <div id="errorWrapper" hidden='true'>
                <div id="errorMessageLeft">
                    <span id="errorMessage"></span>
                    <button id="errorShowMore" data-l10n-id="error_more_info">
                        More Information
                    </button>
                    <button id="errorShowLess" data-l10n-id="error_less_info" hidden='true'>
                        Less Information
                    </button>
                </div>
                <div id="errorMessageRight">
                    <button id="errorClose" data-l10n-id="error_close">
                        Close
                    </button>
                </div>
                <div class="clearBoth"></div>
                <textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
            </div>
        </div> <!-- mainContainer -->

        <div id="overlayContainer" class="hidden">
            <div id="passwordOverlay" class="container hidden">
                <div class="dialog">
                    <div class="row">
                        <p id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</p>
                    </div>
                    <div class="row">
                        <!-- The type="password" attribute is set via script, to prevent warnings in Firefox for all http:// documents. -->
                        <input id="password" class="toolbarField">
                    </div>
                    <div class="buttonRow">
                        <button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
                        <button id="passwordSubmit" class="overlayButton"><span data-l10n-id="password_ok">OK</span></button>
                    </div>
                </div>
            </div>
            <div id="documentPropertiesOverlay" class="container hidden">
                <div class="dialog">
                    <div class="row">
                        <span data-l10n-id="document_properties_file_name">File name:</span> <p id="fileNameField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_file_size">File size:</span> <p id="fileSizeField">-</p>
                    </div>
                    <div class="separator"></div>
                    <div class="row">
                        <span data-l10n-id="document_properties_title">Title:</span> <p id="titleField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_author">Author:</span> <p id="authorField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_subject">Subject:</span> <p id="subjectField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_keywords">Keywords:</span> <p id="keywordsField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_creation_date">Creation Date:</span> <p id="creationDateField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_modification_date">Modification Date:</span> <p id="modificationDateField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_creator">Creator:</span> <p id="creatorField">-</p>
                    </div>
                    <div class="separator"></div>
                    <div class="row">
                        <span data-l10n-id="document_properties_producer">PDF Producer:</span> <p id="producerField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_version">PDF Version:</span> <p id="versionField">-</p>
                    </div>
                    <div class="row">
                        <span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
                    </div>
                    <div class="buttonRow">
                        <button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>
                    </div>
                </div>
            </div>
            <div id="printServiceOverlay" class="container hidden">
                <div class="dialog">
                    <div class="row">
                        <span data-l10n-id="print_progress_message">Preparing document for printing…</span>
                    </div>
                    <div class="row">
                        <progress value="0" max="100"></progress>
                        <span data-l10n-id="print_progress_percent" data-l10n-args='{ "progress": 0 }' class="relative-progress">0%</span>
                    </div>
                    <div class="buttonRow">
                        <button id="printCancel" class="overlayButton"><span data-l10n-id="print_progress_close">Cancel</span></button>
                    </div>
                </div>
            </div>
        </div>  <!-- overlayContainer -->

    </div> <!-- outerContainer -->
    <div id="printContainer"></div>
</div>
</body>
</html>

main.js

...
btn.onClick = function() {
  PDFViewerApplication.open('ms-appdata:///local/xxxxx/somefile.pdf'); // It loads a file that was downloaded and stored within the app's local storage
}
...

Solution

  • From the error message, you are currently loading some remote web content in the local context, which is not allowed due to safety reason. Please refer to the table of Features and restrictions by context (HTML) for details.

    So, to fix the problem, you can put the loading PDF part into x-ms-webview:

    onDeviceReady in index.js:

    function onDeviceReady() {
        // Handle the Cordova pause and resume events
        document.addEventListener( 'pause', onPause.bind( this ), false );
        document.addEventListener( 'resume', onResume.bind( this ), false );
    
        // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.
            if (cordova.platformId == "windows")
            {
                var webview = document.createElement("x-ms-webview");
                webview.src = "ms-appx-web:///www/pdftest.html";
                webview.width = 500;
                webview.height = 500;
                document.getElementById("main").appendChild(webview);
            }
    };
    

    www\pdftest.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
    </head>
    <body>
        <canvas id="the-canvas"></canvas>
        <script src="lib/pdf.js"></script>
        <script src="scripts/main.js"></script>
    </body>
    </html>
    

    www\main.js:

    var url = 'http://cdn.mozilla.net/pdfjs/helloworld.pdf';
    

    // Disable workers to avoid yet another cross-origin issue (workers need // the URL of the script to be loaded, and dynamically loading a cross-origin // script does not work). // PDFJS.disableWorker = true;

    // The workerSrc property shall be specified. PDFJS.workerSrc = 'http://mozilla.github.io/pdf.js/build/pdf.worker.js';

    // Asynchronous download of PDF var loadingTask = PDFJS.getDocument(url); loadingTask.promise.then(function (pdf) { console.log('PDF loaded');

    // Fetch the first page
    var pageNumber = 1;
    pdf.getPage(pageNumber).then(function (page) {
        console.log('Page loaded');
    
        var scale = 1.5;
        var viewport = page.getViewport(scale);
    
        // Prepare canvas using PDF page dimensions
        var canvas = document.getElementById('the-canvas');
        var context = canvas.getContext('2d');
        canvas.height = viewport.height;
        canvas.width = viewport.width;
    
        // Render PDF page into canvas context
        var renderContext = {
            canvasContext: context,
            viewport: viewport
        };
        var renderTask = page.render(renderContext);
        renderTask.then(function () {
            console.log('Page rendered');
        });
    });
    }, function (reason) {
        // PDF loading error
        console.error(reason);
    });
    

    And here is the complete test demo:PDFJSCordovaDemo