diff --git a/CMakeLists.txt b/CMakeLists.txt index 68259920..d8d64bd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,9 @@ file(GLOB SOURCES ${CMAKE_SOURCE_DIR}/src/main/cc/*.cc) file(GLOB IMPL_SOURCES ${CMAKE_SOURCE_DIR}/src/main/cc/impl/*.cc) file(GLOB SHAPER_SOURCES ${CMAKE_SOURCE_DIR}/src/main/cc/shaper/*.cc) file(GLOB PARAGRAPH_SOURCES ${CMAKE_SOURCE_DIR}/src/main/cc/paragraph/*.cc) +file(GLOB PDF_SOURCES ${CMAKE_SOURCE_DIR}/src/main/cc/pdf/*.cc) add_definitions(-DSK_GL -DSK_SHAPER_HARFBUZZ_AVAILABLE) -add_library(skija SHARED ${SOURCES} ${IMPL_SOURCES} ${SHAPER_SOURCES} ${PARAGRAPH_SOURCES}) +add_library(skija SHARED ${SOURCES} ${IMPL_SOURCES} ${SHAPER_SOURCES} ${PARAGRAPH_SOURCES} ${PDF_SOURCES}) # JNI if(APPLE) diff --git a/src/main/cc/Font.cc b/src/main/cc/Font.cc index bf3f26cb..763f23ab 100644 --- a/src/main/cc/Font.cc +++ b/src/main/cc/Font.cc @@ -253,6 +253,17 @@ extern "C" JNIEXPORT jobject JNICALL Java_org_jetbrains_skija_Font__1nMeasureTex return skija::Rect::fromSkRect(env, bounds); } +extern "C" JNIEXPORT jfloat JNICALL Java_org_jetbrains_skija_Font__1nMeasureTextWidth + (JNIEnv* env, jclass jclass, jlong ptr, jstring str, jlong paintPtr) { + SkFont* instance = reinterpret_cast(static_cast(ptr)); + SkPaint* paint = reinterpret_cast(static_cast(paintPtr)); + jsize len = env->GetStringLength(str); + const jchar* chars = env->GetStringChars(str, nullptr); + float width = instance->measureText(chars, len * sizeof(jchar), SkTextEncoding::kUTF16, nullptr, paint); + env->ReleaseStringChars(str, chars); + return width; +} + extern "C" JNIEXPORT jfloatArray JNICALL Java_org_jetbrains_skija_Font__1nGetWidths (JNIEnv* env, jclass jclass, jlong ptr, jshortArray glyphsArr) { SkFont* instance = reinterpret_cast(static_cast(ptr)); diff --git a/src/main/cc/pdf/Document.cc b/src/main/cc/pdf/Document.cc new file mode 100644 index 00000000..e264a98b --- /dev/null +++ b/src/main/cc/pdf/Document.cc @@ -0,0 +1,108 @@ +#include +#include +#include "include/docs/SkPDFDocument.h" +#include "SkCanvas.h" +#include "SkStream.h" +#include "SkRect.h" +#include "SkPictureRecorder.h" + +struct PageRecord { + PageRecord(int width, int height, const SkRect& contentRect) + : mPictureRecorder(new SkPictureRecorder()) + , mPicture(NULL) + , mWidth(width) + , mHeight(height) { + mContentRect = contentRect; + } + ~PageRecord() { + delete mPictureRecorder; + if (NULL != mPicture) { + mPicture->unref(); + } + } + SkPictureRecorder* mPictureRecorder; + SkPicture* mPicture; + const int mWidth; + const int mHeight; + SkRect mContentRect; +}; + +class Document { +public: + Document() { + mCurrentPage = NULL; + } + SkCanvas* startPage(int width, int height, + int contentLeft, int contentTop, int contentRight, int contentBottom) { + assert(mCurrentPage == NULL); + SkRect contentRect = SkRect::MakeLTRB( + contentLeft, contentTop, contentRight, contentBottom); + PageRecord* page = new PageRecord(width, height, contentRect); + mPages.push_back(page); + mCurrentPage = page; + SkCanvas* canvas = page->mPictureRecorder->beginRecording( + SkRect::MakeWH(contentRect.width(), contentRect.height())); + return canvas; + } + void finishPage() { + assert(mCurrentPage != NULL); + assert(mCurrentPage->mPictureRecorder != NULL); + assert(mCurrentPage->mPicture == NULL); + mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->finishRecordingAsPicture().release(); + delete mCurrentPage->mPictureRecorder; + mCurrentPage->mPictureRecorder = NULL; + mCurrentPage = NULL; + } + void write(SkWStream* stream) { + sk_sp document = SkPDF::MakeDocument(stream); + for (unsigned i = 0; i < mPages.size(); i++) { + PageRecord* page = mPages[i]; + SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight, + &(page->mContentRect)); + canvas->drawPicture(page->mPicture); + document->endPage(); + } + document->close(); + } + void close() { + assert(NULL == mCurrentPage); + for (unsigned i = 0; i < mPages.size(); i++) { + delete mPages[i]; + } + } +private: + ~Document() { + close(); + } + std::vector mPages; + PageRecord* mCurrentPage; +}; + +extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skija_pdf_Document__1nMake(JNIEnv* env, jclass jclass) { + return reinterpret_cast(new Document()); +} + +extern "C" JNIEXPORT jlong JNICALL Java_org_jetbrains_skija_pdf_Document__1nBeginPage + (JNIEnv* env, jclass jclass, jlong ptr, jfloat width, jfloat height/*, jfloat left, jfloat top, jfloat right, jfloat bottom*/) { + Document* instance = reinterpret_cast(static_cast(ptr)); + SkCanvas* canvas = instance->startPage(width, height, 0, 0, width, height); + return reinterpret_cast(canvas); +} + +extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skija_pdf_Document__1nWrite(JNIEnv* env, jclass jclass, jlong ptr, jstring pathStr) { + Document* document = reinterpret_cast(ptr); + const char* path = env->GetStringUTFChars(pathStr, nullptr); + SkFILEWStream out(path); + env->ReleaseStringUTFChars(pathStr, path); + document->write(&out); +} + +extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skija_pdf_Document__1nEndPage(JNIEnv* env, jclass jclass, jlong ptr) { + Document* document = reinterpret_cast(ptr); + document->finishPage(); +} +extern "C" JNIEXPORT void JNICALL Java_org_jetbrains_skija_pdf_Document__1nClose(JNIEnv* env, jclass jclass, jlong ptr) { + Document* document = reinterpret_cast(ptr); + document->close(); +} + diff --git a/src/main/java/org/jetbrains/skija/Font.java b/src/main/java/org/jetbrains/skija/Font.java index 80c0e791..141c2137 100644 --- a/src/main/java/org/jetbrains/skija/Font.java +++ b/src/main/java/org/jetbrains/skija/Font.java @@ -369,6 +369,16 @@ public Rect measureText(String s, Paint p) { return _nMeasureText(_ptr, s, Native.getPtr(p)); } + public float measureTextWidth(String s) { + Stats.onNativeCall(); + return measureTextWidth(s, null); + } + + public float measureTextWidth(String s, Paint p) { + Stats.onNativeCall(); + return _nMeasureTextWidth(_ptr, s, Native.getPtr(p)); + } + /** * Retrieves the advances for each glyph */ @@ -502,6 +512,7 @@ public TextBlob shape(String str, float width) { @ApiStatus.Internal public static native short[] _nGetUTF32GlyphIds(long ptr, int[] uni); @ApiStatus.Internal public static native int _nGetStringGlyphsCount(long ptr, String str); @ApiStatus.Internal public static native Rect _nMeasureText(long ptr, String str, long paintPtr); + @ApiStatus.Internal public static native float _nMeasureTextWidth(long ptr, String str, long paintPtr); @ApiStatus.Internal public static native float[] _nGetWidths(long ptr, short[] glyphs); @ApiStatus.Internal public static native Rect[] _nGetBounds(long ptr, short[] glyphs, long paintPtr); @ApiStatus.Internal public static native Point[] _nGetPositions(long ptr, short[] glyphs, float x, float y); diff --git a/src/main/java/org/jetbrains/skija/pdf/Document.java b/src/main/java/org/jetbrains/skija/pdf/Document.java new file mode 100644 index 00000000..8971b6b6 --- /dev/null +++ b/src/main/java/org/jetbrains/skija/pdf/Document.java @@ -0,0 +1,48 @@ +package org.jetbrains.skija.pdf; + +import org.jetbrains.skija.Canvas; +import org.jetbrains.skija.impl.Native; +import org.jetbrains.skija.impl.Stats; + +public class Document extends Native { + public Document() { + this(_nMake()); + Stats.onNativeCall(); + } + + public Document(long ptr) { + super(ptr); + } + + public Canvas beginPage(float width, float height) { + Stats.onNativeCall(); + return new Canvas(_nBeginPage(_ptr, width, height)); + } + + public void endPage() { + Stats.onNativeCall(); + _nEndPage(_ptr); + } + + public void writeTo(String path) { + Stats.onNativeCall(); + _nWrite(_ptr, path); + } + + public void close() { + Stats.onNativeCall(); + _nClose(_ptr); + } + + public static native long _nMake(); + + public static native long _nGetFinalizer(); + + public static native long _nBeginPage(long ptr, float width, float height); + + public static native void _nEndPage(long ptr); + + public static native void _nWrite(long ptr, String path); + + public static native void _nClose(long ptr); +}