Revert "Move PdfRenderer java and native code to packages/providers/MediaProvider"
This reverts commit d84522ce1ff9ffd5b24d3b8d8891cd49491894f2. Reason for revert: unblocking 24Q2 release, b/326312780 API-Coverage-Bug: b/326587267 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5b11e0b49b2955407a6e6435bbc97fb6174b3ffd) Merged-In: I6f3f51a22082b702e8cc304fef90c8a6e6504152 Change-Id: I6f3f51a22082b702e8cc304fef90c8a6e6504152
This commit is contained in:
parent
094b91ec3c
commit
89090a3cd0
@ -18053,6 +18053,24 @@ package android.graphics.pdf {
|
||||
method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
|
||||
}
|
||||
|
||||
public final class PdfRenderer implements java.lang.AutoCloseable {
|
||||
ctor public PdfRenderer(@NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
|
||||
method public void close();
|
||||
method public int getPageCount();
|
||||
method public android.graphics.pdf.PdfRenderer.Page openPage(int);
|
||||
method public boolean shouldScaleForPrinting();
|
||||
}
|
||||
|
||||
public final class PdfRenderer.Page implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method public int getHeight();
|
||||
method public int getIndex();
|
||||
method public int getWidth();
|
||||
method public void render(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @Nullable android.graphics.Matrix, int);
|
||||
field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
|
||||
field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.graphics.text {
|
||||
|
@ -25,9 +25,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -39,12 +37,6 @@ import java.io.IOException;
|
||||
*/
|
||||
public final class PdfEditor {
|
||||
|
||||
/**
|
||||
* Any call the native pdfium code has to be single threaded as the library does not support
|
||||
* parallel use.
|
||||
*/
|
||||
private static final Object sPdfiumLock = new Object();
|
||||
|
||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||
|
||||
private long mNativeDocument;
|
||||
@ -87,7 +79,7 @@ public final class PdfEditor {
|
||||
}
|
||||
mInput = input;
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
mNativeDocument = nativeOpen(mInput.getFd(), size);
|
||||
try {
|
||||
mPageCount = nativeGetPageCount(mNativeDocument);
|
||||
@ -120,7 +112,7 @@ public final class PdfEditor {
|
||||
throwIfClosed();
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
|
||||
}
|
||||
}
|
||||
@ -146,12 +138,12 @@ public final class PdfEditor {
|
||||
Point size = new Point();
|
||||
getPageSize(pageIndex, size);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
|
||||
0, 0, size.x, size.y);
|
||||
}
|
||||
} else {
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
|
||||
clip.left, clip.top, clip.right, clip.bottom);
|
||||
}
|
||||
@ -169,7 +161,7 @@ public final class PdfEditor {
|
||||
throwIfOutSizeNull(outSize);
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeGetPageSize(mNativeDocument, pageIndex, outSize);
|
||||
}
|
||||
}
|
||||
@ -185,7 +177,7 @@ public final class PdfEditor {
|
||||
throwIfOutMediaBoxNull(outMediaBox);
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
|
||||
}
|
||||
}
|
||||
@ -201,7 +193,7 @@ public final class PdfEditor {
|
||||
throwIfMediaBoxNull(mediaBox);
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
|
||||
}
|
||||
}
|
||||
@ -217,7 +209,7 @@ public final class PdfEditor {
|
||||
throwIfOutCropBoxNull(outCropBox);
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
|
||||
}
|
||||
}
|
||||
@ -233,7 +225,7 @@ public final class PdfEditor {
|
||||
throwIfCropBoxNull(cropBox);
|
||||
throwIfPageNotInDocument(pageIndex);
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
|
||||
}
|
||||
}
|
||||
@ -246,7 +238,7 @@ public final class PdfEditor {
|
||||
public boolean shouldScaleForPrinting() {
|
||||
throwIfClosed();
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
return nativeScaleForPrinting(mNativeDocument);
|
||||
}
|
||||
}
|
||||
@ -263,7 +255,7 @@ public final class PdfEditor {
|
||||
try {
|
||||
throwIfClosed();
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeWrite(mNativeDocument, output.getFd());
|
||||
}
|
||||
} finally {
|
||||
@ -295,7 +287,7 @@ public final class PdfEditor {
|
||||
|
||||
private void doClose() {
|
||||
if (mNativeDocument != 0) {
|
||||
synchronized (sPdfiumLock) {
|
||||
synchronized (PdfRenderer.sPdfiumLock) {
|
||||
nativeClose(mNativeDocument);
|
||||
}
|
||||
mNativeDocument = 0;
|
||||
|
502
graphics/java/android/graphics/pdf/PdfRenderer.java
Normal file
502
graphics/java/android/graphics/pdf/PdfRenderer.java
Normal file
@ -0,0 +1,502 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.graphics.pdf;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class enables rendering a PDF document. This class is not thread safe.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you want to render a PDF, you create a renderer and for every page you want
|
||||
* to render, you open the page, render it, and close the page. After you are done
|
||||
* with rendering, you close the renderer. After the renderer is closed it should not
|
||||
* be used anymore. Note that the pages are rendered one by one, i.e. you can have
|
||||
* only a single page opened at any given time.
|
||||
* </p>
|
||||
* <p>
|
||||
* A typical use of the APIs to render a PDF looks like this:
|
||||
* </p>
|
||||
* <pre>
|
||||
* // create a new renderer
|
||||
* PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
|
||||
*
|
||||
* // let us just render all pages
|
||||
* final int pageCount = renderer.getPageCount();
|
||||
* for (int i = 0; i < pageCount; i++) {
|
||||
* Page page = renderer.openPage(i);
|
||||
*
|
||||
* // say we render for showing on the screen
|
||||
* page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
|
||||
*
|
||||
* // do stuff with the bitmap
|
||||
*
|
||||
* // close the page
|
||||
* page.close();
|
||||
* }
|
||||
*
|
||||
* // close the renderer
|
||||
* renderer.close();
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Print preview and print output</h3>
|
||||
* <p>
|
||||
* If you are using this class to rasterize a PDF for printing or show a print
|
||||
* preview, it is recommended that you respect the following contract in order
|
||||
* to provide a consistent user experience when seeing a preview and printing,
|
||||
* i.e. the user sees a preview that is the same as the printout.
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* Respect the property whether the document would like to be scaled for printing
|
||||
* as per {@link #shouldScaleForPrinting()}.
|
||||
* </li>
|
||||
* <li>
|
||||
* When scaling a document for printing the aspect ratio should be preserved.
|
||||
* </li>
|
||||
* <li>
|
||||
* Do not inset the content with any margins from the {@link android.print.PrintAttributes}
|
||||
* as the application is responsible to render it such that the margins are respected.
|
||||
* </li>
|
||||
* <li>
|
||||
* If document page size is greater than the printed media size the content should
|
||||
* be anchored to the upper left corner of the page for left-to-right locales and
|
||||
* top right corner for right-to-left locales.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #close()
|
||||
*/
|
||||
public final class PdfRenderer implements AutoCloseable {
|
||||
/**
|
||||
* Any call the native pdfium code has to be single threaded as the library does not support
|
||||
* parallel use.
|
||||
*/
|
||||
final static Object sPdfiumLock = new Object();
|
||||
|
||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||
|
||||
private final Point mTempPoint = new Point();
|
||||
|
||||
private long mNativeDocument;
|
||||
|
||||
private final int mPageCount;
|
||||
|
||||
private ParcelFileDescriptor mInput;
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
private Page mCurrentPage;
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
Page.RENDER_MODE_FOR_DISPLAY,
|
||||
Page.RENDER_MODE_FOR_PRINT
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RenderMode {}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* <p>
|
||||
* <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
|
||||
* i.e. its data being randomly accessed, e.g. pointing to a file.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note:</strong> This class takes ownership of the passed in file descriptor
|
||||
* and is responsible for closing it when the renderer is closed.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the file is from an untrusted source it is recommended to run the renderer in a separate,
|
||||
* isolated process with minimal permissions to limit the impact of security exploits.
|
||||
* </p>
|
||||
*
|
||||
* @param input Seekable file descriptor to read from.
|
||||
*
|
||||
* @throws java.io.IOException If an error occurs while reading the file.
|
||||
* @throws java.lang.SecurityException If the file requires a password or
|
||||
* the security scheme is not supported.
|
||||
*/
|
||||
public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
|
||||
if (input == null) {
|
||||
throw new NullPointerException("input cannot be null");
|
||||
}
|
||||
|
||||
final long size;
|
||||
try {
|
||||
Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
|
||||
size = Os.fstat(input.getFileDescriptor()).st_size;
|
||||
} catch (ErrnoException ee) {
|
||||
throw new IllegalArgumentException("file descriptor not seekable");
|
||||
}
|
||||
mInput = input;
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
mNativeDocument = nativeCreate(mInput.getFd(), size);
|
||||
try {
|
||||
mPageCount = nativeGetPageCount(mNativeDocument);
|
||||
} catch (Throwable t) {
|
||||
nativeClose(mNativeDocument);
|
||||
mNativeDocument = 0;
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
mCloseGuard.open("close");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this renderer. You should not use this instance
|
||||
* after this method is called.
|
||||
*/
|
||||
public void close() {
|
||||
throwIfClosed();
|
||||
throwIfPageOpened();
|
||||
doClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of pages in the document.
|
||||
*
|
||||
* @return The page count.
|
||||
*/
|
||||
public int getPageCount() {
|
||||
throwIfClosed();
|
||||
return mPageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the document prefers to be scaled for printing.
|
||||
* You should take this info account if the document is rendered
|
||||
* for printing and the target media size differs from the page
|
||||
* size.
|
||||
*
|
||||
* @return If to scale the document.
|
||||
*/
|
||||
public boolean shouldScaleForPrinting() {
|
||||
throwIfClosed();
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
return nativeScaleForPrinting(mNativeDocument);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a page for rendering.
|
||||
*
|
||||
* @param index The page index.
|
||||
* @return A page that can be rendered.
|
||||
*
|
||||
* @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close()
|
||||
*/
|
||||
public Page openPage(int index) {
|
||||
throwIfClosed();
|
||||
throwIfPageOpened();
|
||||
throwIfPageNotInDocument(index);
|
||||
mCurrentPage = new Page(index);
|
||||
return mCurrentPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (mCloseGuard != null) {
|
||||
mCloseGuard.warnIfOpen();
|
||||
}
|
||||
|
||||
doClose();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
private void doClose() {
|
||||
if (mCurrentPage != null) {
|
||||
mCurrentPage.close();
|
||||
mCurrentPage = null;
|
||||
}
|
||||
|
||||
if (mNativeDocument != 0) {
|
||||
synchronized (sPdfiumLock) {
|
||||
nativeClose(mNativeDocument);
|
||||
}
|
||||
mNativeDocument = 0;
|
||||
}
|
||||
|
||||
if (mInput != null) {
|
||||
IoUtils.closeQuietly(mInput);
|
||||
mInput = null;
|
||||
}
|
||||
mCloseGuard.close();
|
||||
}
|
||||
|
||||
private void throwIfClosed() {
|
||||
if (mInput == null) {
|
||||
throw new IllegalStateException("Already closed");
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfPageOpened() {
|
||||
if (mCurrentPage != null) {
|
||||
throw new IllegalStateException("Current page not closed");
|
||||
}
|
||||
}
|
||||
|
||||
private void throwIfPageNotInDocument(int pageIndex) {
|
||||
if (pageIndex < 0 || pageIndex >= mPageCount) {
|
||||
throw new IllegalArgumentException("Invalid page index");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a PDF document page for rendering.
|
||||
*/
|
||||
public final class Page implements AutoCloseable {
|
||||
|
||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||
|
||||
/**
|
||||
* Mode to render the content for display on a screen.
|
||||
*/
|
||||
public static final int RENDER_MODE_FOR_DISPLAY = 1;
|
||||
|
||||
/**
|
||||
* Mode to render the content for printing.
|
||||
*/
|
||||
public static final int RENDER_MODE_FOR_PRINT = 2;
|
||||
|
||||
private final int mIndex;
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
|
||||
private long mNativePage;
|
||||
|
||||
private Page(int index) {
|
||||
Point size = mTempPoint;
|
||||
synchronized (sPdfiumLock) {
|
||||
mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
|
||||
}
|
||||
mIndex = index;
|
||||
mWidth = size.x;
|
||||
mHeight = size.y;
|
||||
mCloseGuard.open("close");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page index.
|
||||
*
|
||||
* @return The index.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page width in points (1/72").
|
||||
*
|
||||
* @return The width in points.
|
||||
*/
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the page height in points (1/72").
|
||||
*
|
||||
* @return The height in points.
|
||||
*/
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a page to a bitmap.
|
||||
* <p>
|
||||
* You may optionally specify a rectangular clip in the bitmap bounds. No rendering
|
||||
* outside the clip will be performed, hence it is your responsibility to initialize
|
||||
* the bitmap outside the clip.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may optionally specify a matrix to transform the content from page coordinates
|
||||
* which are in points (1/72") to bitmap coordinates which are in pixels. If this
|
||||
* matrix is not provided this method will apply a transformation that will fit the
|
||||
* whole page to the destination clip if provided or the destination bitmap if no
|
||||
* clip is provided.
|
||||
* </p>
|
||||
* <p>
|
||||
* The clip and transformation are useful for implementing tile rendering where the
|
||||
* destination bitmap contains a portion of the image, for example when zooming.
|
||||
* Another useful application is for printing where the size of the bitmap holding
|
||||
* the page is too large and a client can render the page in stripes.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note: </strong> The destination bitmap format must be
|
||||
* {@link Config#ARGB_8888 ARGB}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>Note: </strong> The optional transformation matrix must be affine as per
|
||||
* {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify
|
||||
* rotation, scaling, translation but not a perspective transformation.
|
||||
* </p>
|
||||
*
|
||||
* @param destination Destination bitmap to which to render.
|
||||
* @param destClip Optional clip in the bitmap bounds.
|
||||
* @param transform Optional transformation to apply when rendering.
|
||||
* @param renderMode The render mode.
|
||||
*
|
||||
* @see #RENDER_MODE_FOR_DISPLAY
|
||||
* @see #RENDER_MODE_FOR_PRINT
|
||||
*/
|
||||
public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
|
||||
@Nullable Matrix transform, @RenderMode int renderMode) {
|
||||
if (mNativePage == 0) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
destination = Preconditions.checkNotNull(destination, "bitmap null");
|
||||
|
||||
if (destination.getConfig() != Config.ARGB_8888) {
|
||||
throw new IllegalArgumentException("Unsupported pixel format");
|
||||
}
|
||||
|
||||
if (destClip != null) {
|
||||
if (destClip.left < 0 || destClip.top < 0
|
||||
|| destClip.right > destination.getWidth()
|
||||
|| destClip.bottom > destination.getHeight()) {
|
||||
throw new IllegalArgumentException("destBounds not in destination");
|
||||
}
|
||||
}
|
||||
|
||||
if (transform != null && !transform.isAffine()) {
|
||||
throw new IllegalArgumentException("transform not affine");
|
||||
}
|
||||
|
||||
if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
|
||||
throw new IllegalArgumentException("Unsupported render mode");
|
||||
}
|
||||
|
||||
if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
|
||||
throw new IllegalArgumentException("Only single render mode supported");
|
||||
}
|
||||
|
||||
final int contentLeft = (destClip != null) ? destClip.left : 0;
|
||||
final int contentTop = (destClip != null) ? destClip.top : 0;
|
||||
final int contentRight = (destClip != null) ? destClip.right
|
||||
: destination.getWidth();
|
||||
final int contentBottom = (destClip != null) ? destClip.bottom
|
||||
: destination.getHeight();
|
||||
|
||||
// If transform is not set, stretch page to whole clipped area
|
||||
if (transform == null) {
|
||||
int clipWidth = contentRight - contentLeft;
|
||||
int clipHeight = contentBottom - contentTop;
|
||||
|
||||
transform = new Matrix();
|
||||
transform.postScale((float)clipWidth / getWidth(),
|
||||
(float)clipHeight / getHeight());
|
||||
transform.postTranslate(contentLeft, contentTop);
|
||||
}
|
||||
|
||||
// FIXME: This code is planned to be outside the UI rendering module, so it should not
|
||||
// be able to access native instances from Bitmap, Matrix, etc.
|
||||
final long transformPtr = transform.ni();
|
||||
|
||||
synchronized (sPdfiumLock) {
|
||||
nativeRenderPage(mNativeDocument, mNativePage, destination.getNativeInstance(),
|
||||
contentLeft, contentTop, contentRight, contentBottom, transformPtr,
|
||||
renderMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this page.
|
||||
*
|
||||
* @see android.graphics.pdf.PdfRenderer#openPage(int)
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
throwIfClosed();
|
||||
doClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (mCloseGuard != null) {
|
||||
mCloseGuard.warnIfOpen();
|
||||
}
|
||||
|
||||
doClose();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
private void doClose() {
|
||||
if (mNativePage != 0) {
|
||||
synchronized (sPdfiumLock) {
|
||||
nativeClosePage(mNativePage);
|
||||
}
|
||||
mNativePage = 0;
|
||||
}
|
||||
|
||||
mCloseGuard.close();
|
||||
mCurrentPage = null;
|
||||
}
|
||||
|
||||
private void throwIfClosed() {
|
||||
if (mNativePage == 0) {
|
||||
throw new IllegalStateException("Already closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static native long nativeCreate(int fd, long size);
|
||||
private static native void nativeClose(long documentPtr);
|
||||
private static native int nativeGetPageCount(long documentPtr);
|
||||
private static native boolean nativeScaleForPrinting(long documentPtr);
|
||||
private static native void nativeRenderPage(long documentPtr, long pagePtr, long bitmapHandle,
|
||||
int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
|
||||
int renderMode);
|
||||
private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
|
||||
Point outSize);
|
||||
private static native void nativeClosePage(long pagePtr);
|
||||
}
|
@ -427,6 +427,7 @@ cc_defaults {
|
||||
"jni/MovieImpl.cpp",
|
||||
"jni/pdf/PdfDocument.cpp",
|
||||
"jni/pdf/PdfEditor.cpp",
|
||||
"jni/pdf/PdfRenderer.cpp",
|
||||
"jni/pdf/PdfUtils.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
|
@ -70,6 +70,7 @@ extern int register_android_graphics_fonts_Font(JNIEnv* env);
|
||||
extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
|
||||
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
|
||||
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
|
||||
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
|
||||
extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
|
||||
extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
|
||||
extern int register_android_graphics_text_TextShaper(JNIEnv *env);
|
||||
@ -141,6 +142,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env);
|
||||
REG_JNI(register_android_graphics_fonts_FontFamily),
|
||||
REG_JNI(register_android_graphics_pdf_PdfDocument),
|
||||
REG_JNI(register_android_graphics_pdf_PdfEditor),
|
||||
REG_JNI(register_android_graphics_pdf_PdfRenderer),
|
||||
REG_JNI(register_android_graphics_text_MeasuredText),
|
||||
REG_JNI(register_android_graphics_text_LineBreaker),
|
||||
REG_JNI(register_android_graphics_text_TextShaper),
|
||||
|
134
libs/hwui/jni/pdf/PdfRenderer.cpp
Normal file
134
libs/hwui/jni/pdf/PdfRenderer.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PdfUtils.h"
|
||||
|
||||
#include "GraphicsJNI.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "fpdfview.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utils/Log.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static const int RENDER_MODE_FOR_DISPLAY = 1;
|
||||
static const int RENDER_MODE_FOR_PRINT = 2;
|
||||
|
||||
static struct {
|
||||
jfieldID x;
|
||||
jfieldID y;
|
||||
} gPointClassInfo;
|
||||
|
||||
static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
|
||||
jint pageIndex, jobject outSize) {
|
||||
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
|
||||
|
||||
FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
|
||||
if (!page) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"cannot load page");
|
||||
return -1;
|
||||
}
|
||||
|
||||
double width = 0;
|
||||
double height = 0;
|
||||
|
||||
int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
|
||||
if (!result) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"cannot get page size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->SetIntField(outSize, gPointClassInfo.x, width);
|
||||
env->SetIntField(outSize, gPointClassInfo.y, height);
|
||||
|
||||
return reinterpret_cast<jlong>(page);
|
||||
}
|
||||
|
||||
static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
|
||||
FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
|
||||
FPDF_ClosePage(page);
|
||||
}
|
||||
|
||||
static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
|
||||
jlong bitmapPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
|
||||
jlong transformPtr, jint renderMode) {
|
||||
FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
|
||||
|
||||
SkBitmap skBitmap;
|
||||
bitmap::toBitmap(bitmapPtr).getSkBitmap(&skBitmap);
|
||||
|
||||
const int stride = skBitmap.width() * 4;
|
||||
|
||||
FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
|
||||
FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
|
||||
|
||||
int renderFlags = FPDF_REVERSE_BYTE_ORDER;
|
||||
if (renderMode == RENDER_MODE_FOR_DISPLAY) {
|
||||
renderFlags |= FPDF_LCD_TEXT;
|
||||
} else if (renderMode == RENDER_MODE_FOR_PRINT) {
|
||||
renderFlags |= FPDF_PRINTING;
|
||||
}
|
||||
|
||||
SkMatrix matrix = *reinterpret_cast<SkMatrix*>(transformPtr);
|
||||
SkScalar transformValues[6];
|
||||
if (!matrix.asAffine(transformValues)) {
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException",
|
||||
"transform matrix has perspective. Only affine matrices are allowed.");
|
||||
return;
|
||||
}
|
||||
|
||||
FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
|
||||
transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
|
||||
transformValues[SkMatrix::kATransX],
|
||||
transformValues[SkMatrix::kATransY]};
|
||||
|
||||
FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
|
||||
|
||||
FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags);
|
||||
|
||||
skBitmap.notifyPixelsChanged();
|
||||
}
|
||||
|
||||
static const JNINativeMethod gPdfRenderer_Methods[] = {
|
||||
{"nativeCreate", "(IJ)J", (void*) nativeOpen},
|
||||
{"nativeClose", "(J)V", (void*) nativeClose},
|
||||
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
|
||||
{"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
|
||||
{"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
|
||||
{"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
|
||||
{"nativeClosePage", "(J)V", (void*) nativeClosePage}
|
||||
};
|
||||
|
||||
int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
|
||||
int result = RegisterMethodsOrDie(
|
||||
env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
|
||||
NELEM(gPdfRenderer_Methods));
|
||||
|
||||
jclass clazz = FindClassOrDie(env, "android/graphics/Point");
|
||||
gPointClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "I");
|
||||
gPointClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "I");
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user