void printerStream::printText(const QString &txt, bool newLine)
{
    if (fwbdebug)
    {       
        qDebug("printText -------");
        qDebug("pageBody.height(): %d", pageBody.height());
        qDebug("yPos: %d", yPos);
    }

    if (txt.isEmpty()) return;
    if (printer->printerState() == QPrinter::Aborted) return;

    pr.setFont( bodyFont );
    QFontMetrics fm = pr.fontMetrics();
    QRect br = fm.boundingRect(txt);

    if (getYSpace()<br.height())
    {
        flushPage();
        beginPage();   // resets yPos
    }

    if (pageNo>=fromPage && pageNo<=toPage)
    {
        pr.setPen(Qt::black);
        pr.drawText( xmargin, yPos, printer->width()-2*xmargin, br.height(),
                     Qt::TextExpandTabs | Qt::TextDontClip,
                     txt );
    }
    int nlines=1;
    int i=-1;
    while ( (i=txt.indexOf("\n",i+1))>=0 ) nlines++;
    if (newLine) yPos = yPos + nlines*fm.lineSpacing();
}
Exemple #2
0
static void test_abortWithFile(skiatest::Reporter* reporter) {
    SkString tmpDir = skiatest::GetTmpDir();

    if (tmpDir.isEmpty()) {
        ERRORF(reporter, "missing tmpDir.");
        return;
    }

    SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf");
    if (!SkFILEWStream(path.c_str()).isValid()) {
        ERRORF(reporter, "unable to write to: %s", path.c_str());
        return;
    }

    // Make sure doc's destructor is called to flush.
    {
        SkFILEWStream stream(path.c_str());
        auto doc = SkPDF::MakeDocument(&stream);

        SkCanvas* canvas = doc->beginPage(100, 100);
        canvas->drawColor(SK_ColorRED);
        doc->endPage();

        doc->abort();
    }

    FILE* file = fopen(path.c_str(), "r");
    // Test that only the header is written, not the full document.
    char buffer[256];
    REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer));
    fclose(file);
}
Exemple #3
0
static void test_file(skiatest::Reporter* reporter) {
    SkString tmpDir = skiatest::GetTmpDir();
    if (tmpDir.isEmpty()) {
        ERRORF(reporter, "missing tmpDir.");
        return;
    }

    SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf");
    if (!SkFILEWStream(path.c_str()).isValid()) {
        ERRORF(reporter, "unable to write to: %s", path.c_str());
        return;
    }

    {
        SkFILEWStream stream(path.c_str());
        auto doc = SkPDF::MakeDocument(&stream);
        SkCanvas* canvas = doc->beginPage(100, 100);

        canvas->drawColor(SK_ColorRED);
        doc->endPage();
        doc->close();
    }

    FILE* file = fopen(path.c_str(), "r");
    REPORTER_ASSERT(reporter, file != nullptr);
    char header[100];
    REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0);
    REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0);
    fclose(file);
}
Exemple #4
0
DEF_TEST(SkPDF_unicode_metadata, r) {
    REQUIRE_PDF_DOCUMENT(SkPDF_unicode_metadata, r);
    SkPDF::Metadata pdfMetadata;
    pdfMetadata.fTitle   = "𝓐𝓑𝓒𝓓𝓔 𝓕𝓖𝓗𝓘𝓙"; // Out of basic multilingual plane
    pdfMetadata.fAuthor  = "ABCDE FGHIJ"; // ASCII
    pdfMetadata.fSubject = "αβγδε ζηθικ"; // inside  basic multilingual plane
    pdfMetadata.fPDFA = true;
    SkDynamicMemoryWStream wStream;
    {
        auto doc = SkPDF::MakeDocument(&wStream, pdfMetadata);
        doc->beginPage(612, 792)->drawColor(SK_ColorCYAN);
    }
    sk_sp<SkData> data(wStream.detachAsData());
    static const char* expectations[] = {
        "<</Title <FEFFD835DCD0D835DCD1D835DCD2D835DCD3D835DCD40020"
            "D835DCD5D835DCD6D835DCD7D835DCD8D835DCD9>",
        "/Author (ABCDE FGHIJ)",
        "Subject <FEFF03B103B203B303B403B5002003B603B703B803B903BA>",
    };
    for (const char* expectation : expectations) {
        if (!contains(data->bytes(), data->size(), expectation)) {
            ERRORF(r, "PDF expectation missing: '%s'.", expectation);
        }
    }
}
Exemple #5
0
// verify that the PDFA flag does something.
DEF_TEST(SkPDF_pdfa_document, r) {
    REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r);

    SkPDF::Metadata pdfMetadata;
    pdfMetadata.fTitle = "test document";
    pdfMetadata.fCreation = {0, 1999, 12, 5, 31, 23, 59, 59};
    pdfMetadata.fPDFA = true;

    SkDynamicMemoryWStream buffer;
    auto doc = SkPDF::MakeDocument(&buffer, pdfMetadata);
    doc->beginPage(64, 64)->drawColor(SK_ColorRED);
    doc->close();
    sk_sp<SkData> data(buffer.detachAsData());

    static const char* expectations[] = {
        "sRGB IEC61966-2.1",
        "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document",
        "<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>",
        "/Subtype /XML",
        "/CreationDate (D:19991231235959+00'00')>>",
    };
    for (const char* expectation : expectations) {
        if (!contains(data->bytes(), data->size(), expectation)) {
            ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
        }
    }
    pdfMetadata.fProducer = "phoney library";
    pdfMetadata.fPDFA = true;
    doc = SkPDF::MakeDocument(&buffer, pdfMetadata);
    doc->beginPage(64, 64)->drawColor(SK_ColorRED);
    doc->close();
    data = buffer.detachAsData();

    static const char* moreExpectations[] = {
        "/Producer (phoney library)",
        "/ProductionLibrary (Skia/PDF m",
        "<!-- <skia:ProductionLibrary>Skia/PDF m",
        "<pdf:Producer>phoney library</pdf:Producer>",
    };
    for (const char* expectation : moreExpectations) {
        if (!contains(data->bytes(), data->size(), expectation)) {
            ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
        }
    }
}
Exemple #6
0
// This test used to assert without the fix submitted for
// http://code.google.com/p/skia/issues/detail?id=1083.
// SKP files might have invalid glyph ids. This test ensures they are ignored,
// and there is no assert on input data in Debug mode.
static void test_issue1083() {
    SkDynamicMemoryWStream outStream;
    auto doc = SkPDF::MakeDocument(&outStream);
    SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);

    uint16_t glyphID = 65000;
    canvas->drawSimpleText(&glyphID, 2, SkTextEncoding::kGlyphID, 0, 0, SkFont(), SkPaint());

    doc->close();
}
void printerStream::printPixmap(const QPixmap &pm, bool newLine)
{
#if 0
    QPaintDevice *dev = pr.device();
    if (fwbdebug)
    {
        qDebug("printPixmap: width=%d height=%d", pm.width(), pm.height());
        qDebug("printPixmap: printer->resolution()=%d", printer->resolution());
        if (dev)
        {
            qDebug("printPixmap: device parameters:");
            qDebug("             height=%d width=%d",
                   dev->height(), dev->width());
            qDebug("             logicalDpiY=%d logicalDpiX=%d",
                   dev->logicalDpiY(), dev->logicalDpiX());
            qDebug("             physicalDpiY=%d physicalDpiX=%d",
                   dev->physicalDpiY(), dev->physicalDpiX());
        }
    }
#endif

    int target_w = (int)(pm.width() * pixmap_scaling_ratio);
    int target_h = (int)(pm.height() * pixmap_scaling_ratio);

    int pmYOffset = 0;
    while ( getYSpace()<(pm.height()-pmYOffset) )
    {
        int yFrag = pageBody.height() - yPos;
        if (pageNo>=fromPage && pageNo<=toPage)
        {
            if (fwbdebug)
                qDebug("Print pixmap 1: yPos=%d pmYOffset=%d "
                       "yFrag=%d target_w=%d target_h=%d",
                       yPos, pmYOffset, yFrag, target_w, target_h);
            pr.drawPixmap(xmargin, yPos, target_w, target_h,
                          pm,
                          0, pmYOffset, -1, yFrag);
        }
        pmYOffset = pmYOffset + yFrag;
        flushPage();
        beginPage();   // resets yPos
    }
    if (pageNo>=fromPage && pageNo<=toPage)
    {
        if (fwbdebug)
            qDebug("Print pixmap 2: yPos=%d pmYOffset=%d target_w=%d target_h=%d",
                   yPos, pmYOffset, target_w, target_h);
        pr.drawPixmap(xmargin, yPos, target_w, target_h,
                      pm,
                      0, pmYOffset, -1, -1);
    }

    if (newLine) yPos = yPos + (target_h - pmYOffset);
}
Exemple #8
0
DEF_TEST(SkPDF_document_skbug_4734, r) {
    REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r);
    SkDynamicMemoryWStream stream;
    auto doc = SkPDF::MakeDocument(&stream);
    SkCanvas* canvas = doc->beginPage(64, 64);
    canvas->scale(10000.0f, 10000.0f);
    canvas->translate(20.0f, 10.0f);
    canvas->rotate(30.0f);
    const char text[] = "HELLO";
    canvas->drawString(text, 0, 0, SkFont(), SkPaint());
}
Exemple #9
0
// Test to make sure that jobs launched by PDF backend don't cause a segfault
// after calling abort().
DEF_TEST(SkPDF_abort_jobs, rep) {
    SkBitmap b;
    b.allocN32Pixels(612, 792);
    b.eraseColor(0x4F9643A0);
    SkPDF::Metadata metadata;
    std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool();
    metadata.fExecutor = executor.get();
    SkNullWStream dst;
    auto doc = SkPDF::MakeDocument(&dst, metadata);
    doc->beginPage(612, 792)->drawBitmap(b, 0, 0);
    doc->abort();
}
Exemple #10
0
static void test_close(skiatest::Reporter* reporter) {
    SkDynamicMemoryWStream stream;
    auto doc = SkPDF::MakeDocument(&stream);

    SkCanvas* canvas = doc->beginPage(100, 100);
    canvas->drawColor(SK_ColorRED);
    doc->endPage();

    doc->close();

    REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
}
Exemple #11
0
static void test_abort(skiatest::Reporter* reporter) {
    SkDynamicMemoryWStream stream;
    auto doc = SkPDF::MakeDocument(&stream);

    SkCanvas* canvas = doc->beginPage(100, 100);
    canvas->drawColor(SK_ColorRED);
    doc->endPage();

    doc->abort();

    // Test that only the header is written, not the full document.
    REPORTER_ASSERT(reporter, stream.bytesWritten() < 256);
}
Exemple #12
0
// Make sure we excercise the multi-page functionality without problems.
// Add this to args.gn to output the PDF to a file:
//   extra_cflags = [ "-DSK_PDF_TEST_MULTIPAGE=\"/tmp/skpdf_test_multipage.pdf\"" ]
DEF_TEST(SkPDF_multiple_pages, r) {
    REQUIRE_PDF_DOCUMENT(SkPDF_multiple_pages, r);
    int n = 100;
#ifdef SK_PDF_TEST_MULTIPAGE
    SkFILEWStream wStream(SK_PDF_TEST_MULTIPAGE);
#else
    SkDynamicMemoryWStream wStream;
#endif
    auto doc = SkPDF::MakeDocument(&wStream);
    for (int i = 0; i < n; ++i) {
        doc->beginPage(612, 792)->drawColor(
                SkColorSetARGB(0xFF, 0x00, (uint8_t)(255.0f * i / (n - 1)), 0x00));
    }
}
Exemple #13
0
// Here is an example of using Skia’s PDF backend (SkPDF) via the SkDocument
// and SkCanvas APIs.
void WritePDF(SkWStream* outputStream,
              const char* documentTitle,
              void (*writePage)(SkCanvas*, int page),
              int numberOfPages,
              SkSize pageSize) {
    SkPDF::Metadata metadata;
    metadata.fTitle = documentTitle;
    metadata.fCreator = "Example WritePDF() Function";
    metadata.fCreation = {0, 2019, 1, 4, 31, 12, 34, 56};
    metadata.fModified = {0, 2019, 1, 4, 31, 12, 34, 56};
    auto pdfDocument = SkPDF::MakeDocument(outputStream, metadata);
    SkASSERT(pdfDocument);
    for (int page = 0; page < numberOfPages; ++page) {
        SkCanvas* pageCanvas = pdfDocument->beginPage(pageSize.width(),
                                                      pageSize.height());
        writePage(pageCanvas, page);
        pdfDocument->endPage();
    }
    pdfDocument->close();
}
void printerStream::printQTable(QTableView *tbl, bool left_margin,
                                bool top_margin)
{
    if (fwbdebug)
    {
        qDebug("printQTable ----------------------------------------------");
        qDebug("Size: %dx%d", tbl->width(), tbl->height());
//        qDebug("Visible: %dx%d",
//               tbl->contentsRect().width(), tbl->contentsRect().height());
//        qDebug("Viewport: %dx%d",
//               tbl->viewport()->width(), tbl->viewport()->height());
//        qDebug("pageBody.height(): %d", pageBody.height());
        qDebug("YSpace: %d", getYSpace());
        qDebug("yPos: %d", yPos);
    }

    int top_row = 0;
    int bottom_row = 1;

    int columnsWidth = 0;
    int i = 0;
    while (i < tbl->model()->columnCount())
    {
        columnsWidth += tbl->columnWidth(i);
        i++;
    }

    int rowCount = tbl->model()->rowCount();
    while (top_row <= (rowCount-1))
    {
        int row = 0;

        int tblHeight = (int)(
            (float)(tbl->horizontalHeader()->height()) * pixmap_scaling_ratio);

        /* ===================================================================
         * Row height is screen pixels, getYSpace returns remaining
         * space in printer resolution units. Keep track of both to
         * resize pixmap
         * ===================================================================
         */
        int pixMapHeight = tbl->horizontalHeader()->height();
        for (row=top_row; row < rowCount; ++row)
        {
            if (tbl->isRowHidden(row))
            {
                // hidden rows count but do not contribute to table height
                continue;
            }

            int nth = tblHeight +
                (int)((float)(tbl->rowHeight(row)) * pixmap_scaling_ratio);

            if ( nth==getYSpace() )  break;

            if ( nth>getYSpace() ) 
            { 
                row--; 
                break; 
            }

            tblHeight = nth;
            pixMapHeight += tbl->rowHeight(row);
        }
        
        // if row < top_row then even single row does not fit on the page
        if (row < top_row)
        {
            row = top_row;
            pixMapHeight = tbl->rowHeight(top_row);
        }

        if (row == rowCount) row--;

        bottom_row = row;

        int left_hdr_w = 0;
        if (left_margin && tbl->verticalHeader() != NULL)
            left_hdr_w = tbl->verticalHeader()->width();

        int top_hdr_h = 0;
        if (top_margin && tbl->horizontalHeader() != NULL)
            top_hdr_h = tbl->horizontalHeader()->height();

        int tblWidth = columnsWidth + left_hdr_w;

        if (fwbdebug)
            qDebug("Page %d -- (%d-%d of %d rows) tblWidth: %d   tblHeight: %d",
                   pageNo, top_row, bottom_row, rowCount, tblWidth, tblHeight);

        tbl->resize(tblWidth, pixMapHeight);

        tbl->verticalHeader()->resize(
            tbl->verticalHeader()->width(),
            tbl->height() - tbl->horizontalHeader()->height());
        tbl->horizontalHeader()->resize(
            tbl->width() - tbl->verticalHeader()->width(),
            tbl->horizontalHeader()->height());


// QTableView::scrollTo() makes row visible, but if there are not enough
// rows below it, it appears in the middle of the table. This means the table
// shows few rows that belong on the previous page, which is bad.
//
//        tbl->scrollTo(tbl->model()->index(top_row, 0),
//                      QAbstractItemView::PositionAtTop);

        int top_row_position = tbl->verticalHeader()->sectionPosition(top_row);
        tbl->verticalHeader()->setOffset(top_row_position);

        tbl->update();


        printPixmap(QPixmap::grabWidget(tbl));  //,0,0,-1,pixMapHeight));

        if (bottom_row>=(rowCount-1)) break;

        flushPage();
        beginPage();

        top_row = bottom_row + 1;

    }
}
void printerStream::printRuleSetView(RuleSetView *tbl, bool top_margin)
{
    if (fwbdebug)
    {
        qDebug("printQTable ----------------------------------------------");
        qDebug("Size: %dx%d", tbl->width(), tbl->height());
        qDebug("YSpace: %d", getYSpace());
        qDebug("yPos: %d", yPos);
    }

    int columnsWidth = 0;
    int i = 0;

    while (i < tbl->model()->columnCount())
    {
        columnsWidth += tbl->columnWidth(i);
        i++;
    }

    RuleSetModelIterator it = ((RuleSetModel*)tbl->model())->begin();
    RuleSetModelIterator end = ((RuleSetModel*)tbl->model())->end();

    RuleSetModelIterator bottomIt;

    while (it.isValid() && it != end)
    {
        // Pages iterations

        int tblHeight = (int)(
            (float)(tbl->header()->height()) * pixmap_scaling_ratio);

        /* ===================================================================
         * Row height is screen pixels, getYSpace returns remaining
         * space in printer resolution units. Keep track of both to
         * resize pixmap
         * ===================================================================
         */
        int pixMapHeight = tbl->header()->height();


        RuleSetModelIterator pit = it;
        while (pit != end)
        {

            // Check if current index is collapsed
            QModelIndex index = pit.index();
            QModelIndex parent = index.parent();
            if (!parent.isValid() || tbl->isExpanded(parent))
            {

                int nth = tblHeight +
                    (int)((float)(tbl->rowHeight(index)) * pixmap_scaling_ratio);

                if ( nth==getYSpace() )  break;

                if ( nth>getYSpace() )
                {
                    // if it == pit then even single row does not fit on the page
                    if (it == pit)
                    {
                        pixMapHeight = tbl->rowHeight(index);
                    } else
                    {
                        --pit;
                    }
                    break;
                }

                tblHeight = nth;
                pixMapHeight += tbl->rowHeight(index);
            }

            ++pit;
        }

        bottomIt = pit;

        int left_hdr_w = 0;

        int top_hdr_h = 0;
        if (top_margin && tbl->header() != NULL)
            top_hdr_h = tbl->header()->height();

        int tblWidth = columnsWidth + left_hdr_w;


            qDebug("Page %d -- tblWidth: %d   tblHeight: %d",
                   pageNo, tblWidth, tblHeight);

        tbl->resize(tblWidth, pixMapHeight);
        tbl->updateWidget();

        tbl->scrollTo(it.index(), QAbstractItemView::PositionAtTop);

        printPixmap(QPixmap::grabWidget(tbl));

        if (bottomIt == end) break;

        flushPage();
        beginPage();

        it = bottomIt;
        ++it;
    }
}