summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2014-10-31 19:54:02 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-10-31 19:54:05 +0000
commit93134ce87e7b33e599c9ef9ed8b19ec2556ca8f1 (patch)
treec6aba8a01062d9685aa666cec168f8d1d743103d
parentb1ecf0d776a2dce5d60802f83fb97c893ba42bf1 (diff)
parentbec22beb99b279d381f720d761ca75fe3e7414dc (diff)
downloadframeworks_base-93134ce87e7b33e599c9ef9ed8b19ec2556ca8f1.zip
frameworks_base-93134ce87e7b33e599c9ef9ed8b19ec2556ca8f1.tar.gz
frameworks_base-93134ce87e7b33e599c9ef9ed8b19ec2556ca8f1.tar.bz2
Merge "Save to a PDF file should look like print preview." into lmp-mr1-dev
-rw-r--r--core/jni/android/graphics/pdf/PdfEditor.cpp204
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java155
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl2
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java109
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java38
5 files changed, 491 insertions, 17 deletions
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 5f60c9e..2b756e2 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -19,6 +19,9 @@
#include "fpdfview.h"
#include "fpdfedit.h"
#include "fpdfsave.h"
+#include "fsdk_rendercontext.h"
+#include "fpdf_transformpage.h"
+#include "SkMatrix.h"
#include <android_runtime/AndroidRuntime.h>
#include <vector>
@@ -29,6 +32,20 @@
namespace android {
+enum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP};
+
+static struct {
+ jfieldID x;
+ jfieldID y;
+} gPointClassInfo;
+
+static struct {
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
static Mutex sLock;
static int sUnmatchedInitRequestCount = 0;
@@ -144,18 +161,201 @@ static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
}
}
+static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return;
+ }
+
+ CFX_AffineMatrix matrix;
+
+ SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
+
+ SkScalar transformValues[6];
+ skTransform->asAffine(transformValues);
+
+ // PDF's coordinate system origin is left-bottom while in graphics it
+ // is the top-left. So, translate the PDF coordinates to ours.
+ matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight());
+
+ // Apply the transformation what was created in our coordinates.
+ matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+ transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+ transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
+
+ // Translate the result back to PDF coordinates.
+ matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight());
+
+ FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
+ FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+ FPDFPage_TransFormWithClip(page, &transform, &clip);
+
+ FPDF_ClosePage(page);
+}
+
+static void nativeGetPageSize(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 open page");
+ return;
+ }
+
+ double width = 0;
+ double height = 0;
+
+ const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+ if (!result) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot get page size");
+ return;
+ }
+
+ env->SetIntField(outSize, gPointClassInfo.x, width);
+ env->SetIntField(outSize, gPointClassInfo.y, height);
+
+ FPDF_ClosePage(page);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ PageBox pageBox, jobject outBox) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return false;
+ }
+
+ float left;
+ float top;
+ float right;
+ float bottom;
+
+ const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
+ ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
+ : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
+
+ FPDF_ClosePage(page);
+
+ if (!success) {
+ return false;
+ }
+
+ env->SetIntField(outBox, gRectClassInfo.left, (int) left);
+ env->SetIntField(outBox, gRectClassInfo.top, (int) top);
+ env->SetIntField(outBox, gRectClassInfo.right, (int) right);
+ env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom);
+
+ return true;
+}
+
+static jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject outMediaBox) {
+ const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA,
+ outMediaBox);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject outMediaBox) {
+ const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP,
+ outMediaBox);
+ return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ PageBox pageBox, jobject box) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+ if (!page) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "cannot open page");
+ return;
+ }
+
+ const int left = env->GetIntField(box, gRectClassInfo.left);
+ const int top = env->GetIntField(box, gRectClassInfo.top);
+ const int right = env->GetIntField(box, gRectClassInfo.right);
+ const int bottom = env->GetIntField(box, gRectClassInfo.bottom);
+
+ if (pageBox == PAGE_BOX_MEDIA) {
+ FPDFPage_SetMediaBox(page, left, top, right, bottom);
+ } else {
+ FPDFPage_SetCropBox(page, left, top, right, bottom);
+ }
+
+ FPDF_ClosePage(page);
+}
+
+static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject mediaBox) {
+ nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox);
+}
+
+static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+ jobject mediaBox) {
+ nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
+}
+
static JNINativeMethod gPdfEditor_Methods[] = {
{"nativeOpen", "(IJ)J", (void*) nativeOpen},
{"nativeClose", "(J)V", (void*) nativeClose},
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
{"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
- {"nativeWrite", "(JI)V", (void*) nativeWrite}
+ {"nativeWrite", "(JI)V", (void*) nativeWrite},
+ {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip},
+ {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize},
+ {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+ {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox},
+ {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox},
+ {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox},
+ {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox}
};
int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
- return android::AndroidRuntime::registerNativeMethods(
+ const int result = android::AndroidRuntime::registerNativeMethods(
env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
NELEM(gPdfEditor_Methods));
+
+ jclass pointClass = env->FindClass("android/graphics/Point");
+ gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I");
+ gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I");
+
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I");
+ gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I");
+ gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I");
+ gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I");
+
+ return result;
};
};
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 9837139..0b84d29 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -17,6 +17,10 @@
package android.graphics.pdf;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.OsConstants;
@@ -98,6 +102,109 @@ public final class PdfEditor {
}
/**
+ * Sets a transformation and clip for a given page. The transformation matrix if
+ * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If
+ * the clip is null, then no clipping is performed.
+ *
+ * @param pageIndex The page whose transform to set.
+ * @param transform The transformation to apply.
+ * @param clip The clip to apply.
+ */
+ public void setTransformAndClip(int pageIndex, @Nullable Matrix transform,
+ @Nullable Rect clip) {
+ throwIfClosed();
+ throwIfPageNotInDocument(pageIndex);
+ throwIfNotNullAndNotAfine(transform);
+ if (transform == null) {
+ transform = Matrix.IDENTITY_MATRIX;
+ }
+ if (clip == null) {
+ Point size = new Point();
+ getPageSize(pageIndex, size);
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ 0, 0, size.x, size.y);
+ } else {
+ nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+ clip.left, clip.top, clip.right, clip.bottom);
+ }
+ }
+
+ /**
+ * Gets the size of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outSize The size output.
+ */
+ public void getPageSize(int pageIndex, @NonNull Point outSize) {
+ throwIfClosed();
+ throwIfOutSizeNull(outSize);
+ throwIfPageNotInDocument(pageIndex);
+ nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+ }
+
+ /**
+ * Gets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outMediaBox The media box output.
+ */
+ public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) {
+ throwIfClosed();
+ throwIfOutMediaBoxNull(outMediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+ }
+
+ /**
+ * Sets the media box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param mediaBox The media box.
+ */
+ public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) {
+ throwIfClosed();
+ throwIfMediaBoxNull(mediaBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+ }
+
+ /**
+ * Gets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param outCropBox The crop box output.
+ */
+ public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) {
+ throwIfClosed();
+ throwIfOutCropBoxNull(outCropBox);
+ throwIfPageNotInDocument(pageIndex);
+ return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+ }
+
+ /**
+ * Sets the crop box of a given page in mils (1/72").
+ *
+ * @param pageIndex The page index.
+ * @param cropBox The crop box.
+ */
+ public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) {
+ throwIfClosed();
+ throwIfCropBoxNull(cropBox);
+ throwIfPageNotInDocument(pageIndex);
+ nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+ }
+
+ /**
+ * Gets whether the document prefers to be scaled for printing.
+ *
+ * @return Whether to scale the document.
+ */
+ public boolean shouldScaleForPrinting() {
+ throwIfClosed();
+ return nativeScaleForPrinting(mNativeDocument);
+ }
+
+ /**
* Writes the PDF file to the provided destination.
* <p>
* <strong>Note:</strong> This method takes ownership of the passed in file
@@ -154,9 +261,57 @@ public final class PdfEditor {
}
}
+ private void throwIfNotNullAndNotAfine(Matrix matrix) {
+ if (matrix != null && !matrix.isAffine()) {
+ throw new IllegalStateException("Matrix must be afine");
+ }
+ }
+
+ private void throwIfOutSizeNull(Point outSize) {
+ if (outSize == null) {
+ throw new NullPointerException("outSize cannot be null");
+ }
+ }
+
+ private void throwIfOutMediaBoxNull(Rect outMediaBox) {
+ if (outMediaBox == null) {
+ throw new NullPointerException("outMediaBox cannot be null");
+ }
+ }
+
+ private void throwIfMediaBoxNull(Rect mediaBox) {
+ if (mediaBox == null) {
+ throw new NullPointerException("mediaBox cannot be null");
+ }
+ }
+
+ private void throwIfOutCropBoxNull(Rect outCropBox) {
+ if (outCropBox == null) {
+ throw new NullPointerException("outCropBox cannot be null");
+ }
+ }
+
+ private void throwIfCropBoxNull(Rect cropBox) {
+ if (cropBox == null) {
+ throw new NullPointerException("cropBox cannot be null");
+ }
+ }
+
private static native long nativeOpen(int fd, long size);
private static native void nativeClose(long documentPtr);
private static native int nativeGetPageCount(long documentPtr);
private static native int nativeRemovePage(long documentPtr, int pageIndex);
private static native void nativeWrite(long documentPtr, int fd);
+ private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex,
+ long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom);
+ private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize);
+ private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex,
+ Rect outMediaBox);
+ private static native void nativeSetPageCropBox(long documentPtr, int pageIndex,
+ Rect mediaBox);
+ private static native boolean nativeScaleForPrinting(long documentPtr);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
index b450ccb..01cabe1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
@@ -18,6 +18,7 @@ package com.android.printspooler.renderer;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
+import android.print.PrintAttributes;
/**
* Interface for communication with a remote pdf editor.
@@ -25,6 +26,7 @@ import android.print.PageRange;
interface IPdfEditor {
int openDocument(in ParcelFileDescriptor source);
void removePages(in PageRange[] pages);
+ void applyPrintAttributes(in PrintAttributes attributes);
void write(in ParcelFileDescriptor destination);
void closeDocument();
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 00e5051..0462e4d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -87,7 +87,7 @@ public final class PdfManipulationService extends Service {
}
mRenderer = new PdfRenderer(source);
return mRenderer.getPageCount();
- } catch (IOException|IllegalStateException e) {
+ } catch (IOException | IllegalStateException e) {
IoUtils.closeQuietly(source);
Log.e(LOG_TAG, "Cannot open file", e);
return MALFORMED_PDF_FILE_ERROR;
@@ -217,7 +217,7 @@ public final class PdfManipulationService extends Service {
}
mEditor = new PdfEditor(source);
return mEditor.getPageCount();
- } catch (IOException|IllegalStateException e) {
+ } catch (IOException | IllegalStateException e) {
IoUtils.closeQuietly(source);
Log.e(LOG_TAG, "Cannot open file", e);
throw new RemoteException(e.toString());
@@ -246,6 +246,111 @@ public final class PdfManipulationService extends Service {
}
@Override
+ public void applyPrintAttributes(PrintAttributes attributes) {
+ synchronized (mLock) {
+ throwIfNotOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "applyPrintAttributes()");
+ }
+
+ Rect mediaBox = new Rect();
+ Rect cropBox = new Rect();
+ Matrix transform = new Matrix();
+
+ final boolean contentPortrait = attributes.getMediaSize().isPortrait();
+
+ final boolean layoutDirectionRtl = getResources().getConfiguration()
+ .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+ // We do not want to rotate the media box, so take into account orientation.
+ final int dstWidthPts = contentPortrait
+ ? pointsFromMils(attributes.getMediaSize().getWidthMils())
+ : pointsFromMils(attributes.getMediaSize().getHeightMils());
+ final int dstHeightPts = contentPortrait
+ ? pointsFromMils(attributes.getMediaSize().getHeightMils())
+ : pointsFromMils(attributes.getMediaSize().getWidthMils());
+
+ final boolean scaleForPrinting = mEditor.shouldScaleForPrinting();
+
+ final int pageCount = mEditor.getPageCount();
+ for (int i = 0; i < pageCount; i++) {
+ if (!mEditor.getPageMediaBox(i, mediaBox)) {
+ Log.e(LOG_TAG, "Malformed PDF file");
+ return;
+ }
+
+ final int srcWidthPts = mediaBox.width();
+ final int srcHeightPts = mediaBox.height();
+
+ // Update the media box with the desired size.
+ mediaBox.right = dstWidthPts;
+ mediaBox.bottom = dstHeightPts;
+ mEditor.setPageMediaBox(i, mediaBox);
+
+ // Make sure content is top-left after media box resize.
+ transform.setTranslate(0, srcHeightPts - dstHeightPts);
+
+ // Rotate the content if in landscape.
+ if (!contentPortrait) {
+ transform.postRotate(270);
+ transform.postTranslate(0, dstHeightPts);
+ }
+
+ // Scale the content if document allows it.
+ final float scale;
+ if (scaleForPrinting) {
+ if (contentPortrait) {
+ scale = Math.min((float) dstWidthPts / srcWidthPts,
+ (float) dstHeightPts / srcHeightPts);
+ transform.postScale(scale, scale);
+ } else {
+ scale = Math.min((float) dstWidthPts / srcHeightPts,
+ (float) dstHeightPts / srcWidthPts);
+ transform.postScale(scale, scale, mediaBox.left, mediaBox.bottom);
+ }
+ } else {
+ scale = 1.0f;
+ }
+
+ // Update the crop box relatively to the media box change, if needed.
+ if (mEditor.getPageCropBox(i, cropBox)) {
+ cropBox.left = (int) (cropBox.left * scale + 0.5f);
+ cropBox.top = (int) (cropBox.top * scale + 0.5f);
+ cropBox.right = (int) (cropBox.right * scale + 0.5f);
+ cropBox.bottom = (int) (cropBox.bottom * scale + 0.5f);
+ cropBox.intersect(mediaBox);
+ mEditor.setPageCropBox(i, cropBox);
+ }
+
+ // If in RTL mode put the content in the logical top-right corner.
+ if (layoutDirectionRtl) {
+ final float dx = contentPortrait
+ ? dstWidthPts - (int) (srcWidthPts * scale + 0.5f) : 0;
+ final float dy = contentPortrait
+ ? 0 : - (dstHeightPts - (int) (srcWidthPts * scale + 0.5f));
+ transform.postTranslate(dx, dy);
+ }
+
+ // Adjust the physical margins if needed.
+ Margins minMargins = attributes.getMinMargins();
+ final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
+ final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
+ final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
+ final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
+
+ Rect clip = new Rect(mediaBox);
+ clip.left += paddingLeftPts;
+ clip.top += paddingTopPts;
+ clip.right -= paddingRightPts;
+ clip.bottom -= paddingBottomPts;
+
+ // Apply the accumulated transforms.
+ mEditor.setTransformAndClip(i, transform, clip);
+ }
+ }
+ }
+
+ @Override
public void write(ParcelFileDescriptor destination) throws RemoteException {
synchronized (mLock) {
try {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 15ea9a7..f361884 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -592,7 +592,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
mDestinationSpinner.post(new Runnable() {
@Override
public void run() {
- shredPagesAndFinish(uri);
+ transformDocumentAndFinish(uri);
}
});
} else if (resultCode == RESULT_CANCELED) {
@@ -922,7 +922,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
startCreateDocumentActivity();
} else {
- shredPagesAndFinish(null);
+ transformDocumentAndFinish(null);
}
}
@@ -1597,8 +1597,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
return true;
}
- private void shredPagesAndFinish(final Uri writeToUri) {
- new PageShredder(this, mPrintJob, mFileProvider, new Runnable() {
+ private void transformDocumentAndFinish(final Uri writeToUri) {
+ // If saving to PDF, apply the attibutes as we are acting as a print service.
+ PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter
+ ? mPrintJob.getAttributes() : null;
+ new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, new Runnable() {
@Override
public void run() {
if (writeToUri != null) {
@@ -1606,7 +1609,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
doFinish();
}
- }).shred();
+ }).transform();
}
private void doFinish() {
@@ -2329,7 +2332,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
}
}
- private static final class PageShredder implements ServiceConnection {
+ private static final class DocumentTransformer implements ServiceConnection {
private static final String TEMP_FILE_PREFIX = "print_job";
private static final String TEMP_FILE_EXTENSION = ".pdf";
@@ -2341,20 +2344,24 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
private final PageRange[] mPagesToShred;
+ private final PrintAttributes mAttributesToApply;
+
private final Runnable mCallback;
- public PageShredder(Context context, PrintJobInfo printJob,
- MutexFileProvider fileProvider, Runnable callback) {
+ public DocumentTransformer(Context context, PrintJobInfo printJob,
+ MutexFileProvider fileProvider, PrintAttributes attributes,
+ Runnable callback) {
mContext = context;
mPrintJob = printJob;
mFileProvider = fileProvider;
mCallback = callback;
mPagesToShred = computePagesToShred(mPrintJob);
+ mAttributesToApply = attributes;
}
- public void shred() {
+ public void transform() {
// If we have only the pages we want, done.
- if (mPagesToShred.length <= 0) {
+ if (mPagesToShred.length <= 0 && mAttributesToApply == null) {
mCallback.run();
return;
}
@@ -2376,14 +2383,14 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
// final and this code is the last one to touch
// them as shredding is the very last step, so the
// UI is not interactive at this point.
- shredPages(editor);
+ doTransform(editor);
updatePrintJob();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
- mContext.unbindService(PageShredder.this);
+ mContext.unbindService(DocumentTransformer.this);
mCallback.run();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -2394,7 +2401,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
/* do nothing */
}
- private void shredPages(IPdfEditor editor) {
+ private void doTransform(IPdfEditor editor) {
File tempFile = null;
ParcelFileDescriptor src = null;
ParcelFileDescriptor dst = null;
@@ -2413,6 +2420,11 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
// Drop the pages.
editor.removePages(mPagesToShred);
+ // Apply print attributes if needed.
+ if (mAttributesToApply != null) {
+ editor.applyPrintAttributes(mAttributesToApply);
+ }
+
// Write the modified PDF to a temp file.
tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION,
mContext.getCacheDir());