diff --git poppler/Annot.cc poppler/Annot.cc index c6c2c745..88b214eb 100644 --- poppler/Annot.cc +++ poppler/Annot.cc @@ -1080,72 +1080,79 @@ AnnotAppearanceCharacs::~AnnotAppearanceCharacs() { if (backColor) delete backColor; if (normalCaption) delete normalCaption; if (rolloverCaption) delete rolloverCaption; if (alternateCaption) delete alternateCaption; if (iconFit) delete iconFit; } //------------------------------------------------------------------------ // AnnotAppearanceBBox //------------------------------------------------------------------------ -AnnotAppearanceBBox::AnnotAppearanceBBox(PDFRectangle *rect) { - origX = rect->x1; - origY = rect->y1; +AnnotAppearanceBBox::AnnotAppearanceBBox(const PDFRectangle& rect) { + origX = rect.x1; + origY = rect.y1; borderWidth = 0; // Initially set the same size as rect minX = 0; minY = 0; - maxX = rect->x2 - rect->x1; - maxY = rect->y2 - rect->y1; + maxX = rect.x2 - rect.x1; + maxY = rect.y2 - rect.y1; } void AnnotAppearanceBBox::extendTo(double x, double y) { if (x < minX) { minX = x; } else if (x > maxX) { maxX = x; } if (y < minY) { minY = y; } else if (y > maxY) { maxY = y; } } void AnnotAppearanceBBox::getBBoxRect(double bbox[4]) const { bbox[0] = minX - borderWidth; bbox[1] = minY - borderWidth; bbox[2] = maxX + borderWidth; bbox[3] = maxY + borderWidth; } +void AnnotAppearanceBBox::getPageRect(PDFRectangle* rect) const { + rect->x1 = getPageXMin(); + rect->y1 = getPageYMin(); + rect->x2 = getPageXMax(); + rect->y2 = getPageYMax(); +} + double AnnotAppearanceBBox::getPageXMin() const { return origX + minX - borderWidth; } double AnnotAppearanceBBox::getPageYMin() const { return origY + minY - borderWidth; } double AnnotAppearanceBBox::getPageXMax() const { return origX + maxX + borderWidth; } double AnnotAppearanceBBox::getPageYMax() const { return origY + maxY + borderWidth; } //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ @@ -1183,41 +1190,40 @@ Annot::Annot(PDFDoc *docA, Object *dictObject, Object *obj) { refCnt = 1; if (obj->isRef()) { hasRef = gTrue; ref = obj->getRef(); } else { hasRef = gFalse; } flags = flagUnknown; type = typeUnknown; annotObj = dictObject->copy(); initialize (docA, dictObject->getDict()); } void Annot::initialize(PDFDoc *docA, Dict *dict) { Object apObj, asObj, obj1; ok = gTrue; doc = docA; xref = doc->getXRef(); appearStreams = nullptr; - appearBBox = nullptr; appearState = nullptr; fontSize = 0; appearance.setToNull(); //----- parse the rectangle rect = new PDFRectangle(); obj1 = dict->lookup("Rect"); if (obj1.isArray() && obj1.arrayGetLength() == 4) { Object obj2; (obj2 = obj1.arrayGet(0), obj2.isNum() ? rect->x1 = obj2.getNum() : rect->x1 = 0); (obj2 = obj1.arrayGet(1), obj2.isNum() ? rect->y1 = obj2.getNum() : rect->y1 = 0); (obj2 = obj1.arrayGet(2), obj2.isNum() ? rect->x2 = obj2.getNum() : rect->x2 = 1); (obj2 = obj1.arrayGet(3), obj2.isNum() ? rect->y2 = obj2.getNum() : rect->y2 = 1); if (rect->x1 > rect->x2) { double t = rect->x1; rect->x1 = rect->x2; rect->x2 = t; } @@ -1475,67 +1481,61 @@ void Annot::setPage(int pageIndex, GBool updateP) { Ref pageRef = pageobj->getRef(); obj1 = Object(pageRef.num, pageRef.gen); page = pageIndex; } else { page = 0; } if (updateP) { update("P", std::move(obj1)); } } void Annot::setAppearanceState(const char *state) { annotLocker(); if (!state) return; delete appearState; appearState = new GooString(state); - delete appearBBox; - appearBBox = nullptr; - update ("AS", Object(objName, state)); // The appearance state determines the current appearance stream if (appearStreams) { appearance = appearStreams->getAppearanceStream(AnnotAppearance::appearNormal, appearState->getCString()); } else { appearance.setToNull(); } } void Annot::invalidateAppearance() { annotLocker(); if (appearStreams) { // Remove existing appearance streams appearStreams->removeAllStreams(); } delete appearStreams; appearStreams = nullptr; delete appearState; appearState = nullptr; - delete appearBBox; - appearBBox = nullptr; - appearance.setToNull(); Object obj2 = annotObj.dictLookup("AP"); if (!obj2.isNull()) update ("AP", Object(objNull)); // Remove AP obj2 = annotObj.dictLookup("AS"); if (!obj2.isNull()) update ("AS", Object(objNull)); // Remove AS } double Annot::getXMin() { return rect->x1; } double Annot::getYMin() { return rect->y1; } double Annot::getXMax() { @@ -1576,41 +1576,40 @@ void Annot::decRefCnt() { #endif delete this; return; } #ifdef MULTITHREADED gUnlockMutex(&mutex); #endif } Annot::~Annot() { delete rect; delete contents; if (name) delete name; if (modified) delete modified; delete appearStreams; - delete appearBBox; if (appearState) delete appearState; if (border) delete border; if (color) delete color; #ifdef MULTITHREADED gDestroyMutex(&mutex); #endif } void AnnotAppearanceBuilder::setDrawColor(const AnnotColor *drawColor, GBool fill) { const double *values = drawColor->getValues(); switch (drawColor->getSpace()) { case AnnotColor::colorCMYK: @@ -1711,40 +1710,52 @@ void AnnotAppearanceBuilder::drawCircleBottomRight(double cx, double cy, double r2 = r / sqrt(2.0); appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx - r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx + (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx + r2, cy + r2); appearBuf->append("S\n"); } +PDFRectangle Annot::getRectFromAnnotObj() const { + PDFRectangle rect; + Object obj1 = annotObj.dictLookup("Rect"); + assert(obj1.isArray() && obj1.arrayGetLength() == 4); + Object obj2; + (obj2 = obj1.arrayGet(0), assert(obj2.isNum()), rect.x1 = obj2.getNum()); + (obj2 = obj1.arrayGet(1), assert(obj2.isNum()), rect.y1 = obj2.getNum()); + (obj2 = obj1.arrayGet(2), assert(obj2.isNum()), rect.x2 = obj2.getNum()); + (obj2 = obj1.arrayGet(3), assert(obj2.isNum()), rect.y2 = obj2.getNum()); + return rect; +} + Object Annot::createForm(const GooString *appearBuf, double *bbox, GBool transparencyGroup, Dict *resDict) { Dict *appearDict = new Dict(xref); appearDict->set("Length", Object(appearBuf->getLength())); appearDict->set("Subtype", Object(objName, "Form")); Array *a = new Array(xref); a->add(Object(bbox[0])); a->add(Object(bbox[1])); a->add(Object(bbox[2])); a->add(Object(bbox[3])); appearDict->set("BBox", Object(a)); if (transparencyGroup) { Dict *d = new Dict(xref); d->set("S", Object(objName, "Transparency")); appearDict->set("Group", Object(d)); } if (resDict) appearDict->set("Resources", Object(resDict)); Stream *mStream = new AutoFreeMemStream(copyString(appearBuf->getCString()), 0, @@ -1803,48 +1814,56 @@ GBool Annot::isVisible(GBool printing) { if (! optContentConfig->optContentIsVisible(&oc)) return gFalse; } return gTrue; } int Annot::getRotation() const { Page *pageobj = doc->getPage(page); assert(pageobj != nullptr); if (flags & flagNoRotate) { return (360 - pageobj->getRotate()) % 360; } else { return 0; } } void Annot::draw(Gfx *gfx, GBool printing) { - annotLocker(); if (!isVisible (printing)) return; - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); + annotLocker(); + + Object obj = makeAppearance(gfx->getXRef()); + drawAppearance(gfx, obj); +} + +Object Annot::makeAppearance(XRef* xref) { + return appearance.fetch(xref); +} + +void Annot::drawAppearance(Gfx *gfx, Object& obj) { gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); } //------------------------------------------------------------------------ // AnnotPopup //------------------------------------------------------------------------ AnnotPopup::AnnotPopup(PDFDoc *docA, PDFRectangle *rect) : Annot(docA, rect) { type = typePopup; annotObj.dictSet ("Subtype", Object(objName, "Popup")); initialize (docA, annotObj.getDict()); } AnnotPopup::AnnotPopup(PDFDoc *docA, Object *dictObject, Object *obj) : Annot(docA, dictObject, obj) { type = typePopup; initialize(docA, dictObject->getDict()); } @@ -2407,104 +2426,91 @@ void AnnotText::setIcon(GooString *new_icon) { "0.729412 0.741176 0.713725 RG 18 6 m 6 18 l S\n" \ "6 6 m 18 18 l S\n" #define ANNOT_TEXT_AP_CIRCLE \ "4.301 23 m 19.699 23 l 21.523 23 23 21.523 23 19.699 c 23 4.301 l 23\n" \ "2.477 21.523 1 19.699 1 c 4.301 1 l 2.477 1 1 2.477 1 4.301 c 1 19.699\n" \ "l 1 21.523 2.477 23 4.301 23 c h\n" \ "4.301 23 m f\n" \ "0.533333 0.541176 0.521569 RG 2.5 w\n" \ "1 J\n" \ "1 j\n" \ "[] 0.0 d\n" \ "4 M 19.5 11.5 m 19.5 7.359 16.141 4 12 4 c 7.859 4 4.5 7.359 4.5 11.5 c 4.5\n" \ "15.641 7.859 19 12 19 c 16.141 19 19.5 15.641 19.5 11.5 c h\n" \ "19.5 11.5 m S\n" \ "0.729412 0.741176 0.713725 RG 19.5 12.5 m 19.5 8.359 16.141 5 12 5 c\n" \ "7.859 5 4.5 8.359 4.5 12.5 c 4.5\n" \ "16.641 7.859 20 12 20 c 16.141 20 19.5 16.641 19.5 12.5 c h\n" \ "19.5 12.5 m S\n" -void AnnotText::draw(Gfx *gfx, GBool printing) { +Object AnnotText::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) appearBuilder.setDrawColor(color, gTrue); else appearBuilder.append ("1 1 1 rg\n"); if (!icon->cmp("Note")) appearBuilder.append (ANNOT_TEXT_AP_NOTE); else if (!icon->cmp("Comment")) appearBuilder.append (ANNOT_TEXT_AP_COMMENT); else if (!icon->cmp("Key")) appearBuilder.append (ANNOT_TEXT_AP_KEY); else if (!icon->cmp("Help")) appearBuilder.append (ANNOT_TEXT_AP_HELP); else if (!icon->cmp("NewParagraph")) appearBuilder.append (ANNOT_TEXT_AP_NEW_PARAGRAPH); else if (!icon->cmp("Paragraph")) appearBuilder.append (ANNOT_TEXT_AP_PARAGRAPH); else if (!icon->cmp("Insert")) appearBuilder.append (ANNOT_TEXT_AP_INSERT); else if (!icon->cmp("Cross")) appearBuilder.append (ANNOT_TEXT_AP_CROSS); else if (!icon->cmp("Circle")) appearBuilder.append (ANNOT_TEXT_AP_CIRCLE); appearBuilder.append ("Q\n"); - // Force 24x24 rectangle - PDFRectangle fixedRect(rect->x1, rect->y2 - 24, rect->x1 + 24, rect->y2); - appearBBox = new AnnotAppearanceBBox(&fixedRect); + // Draw a 24x24 rectangle in appearance XObject coordinate system. + // Gfx::drawAnnot will translate and scale it to Annot Rect. + const PDFRectangle apBBoxRect(0, 0, 24, 24); + AnnotAppearanceBBox appearBBox(apBBoxRect); double bbox[4]; - appearBBox->getBBoxRect(bbox); + appearBBox.getBBoxRect(bbox); if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (appearBBox) { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - appearBBox->getPageXMin(), appearBBox->getPageYMin(), - appearBBox->getPageXMax(), appearBBox->getPageYMax(), - getRotation()); - } else { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - } + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotLink //------------------------------------------------------------------------ AnnotLink::AnnotLink(PDFDoc *docA, PDFRectangle *rect) : Annot(docA, rect) { type = typeLink; annotObj.dictSet ("Subtype", Object(objName, "Link")); initialize (docA, annotObj.getDict()); } AnnotLink::AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj) : Annot(docA, dictObject, obj) { type = typeLink; initialize (docA, dictObject->getDict()); } AnnotLink::~AnnotLink() { @@ -2560,49 +2566,43 @@ void AnnotLink::initialize(PDFDoc *docA, Dict *dict) { uriAction = NULL; } obj1.free(); */ obj1 = dict->lookup("QuadPoints"); if (obj1.isArray()) { quadrilaterals = new AnnotQuadrilaterals(obj1.getArray(), rect); } else { quadrilaterals = nullptr; } obj1 = dict->lookup("BS"); if (obj1.isDict()) { delete border; border = new AnnotBorderBS(obj1.getDict()); } else if (!border) { border = new AnnotBorderBS(); } } -void AnnotLink::draw(Gfx *gfx, GBool printing) { - if (!isVisible (printing)) - return; - - annotLocker(); - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); +void AnnotLink::drawAppearance(Gfx *gfx, Object& obj) { gfx->drawAnnot(&obj, border, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); } //------------------------------------------------------------------------ // AnnotFreeText //------------------------------------------------------------------------ AnnotFreeText::AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da) : AnnotMarkup(docA, rect) { type = typeFreeText; annotObj.dictSet ("Subtype", Object(objName, "FreeText")); annotObj.dictSet("DA", Object(da->copy())); initialize (docA, annotObj.getDict()); } AnnotFreeText::AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj) : AnnotMarkup(docA, dictObject, obj) { type = typeFreeText; initialize(docA, dictObject->getDict()); } @@ -2935,53 +2935,46 @@ void AnnotFreeText::generateFreeTextAppearance() font->decRefCnt(); delete fontcolor; appearBuilder.append ("ET Q\n"); double bbox[4]; bbox[0] = bbox[1] = 0; bbox[2] = rect->x2 - rect->x1; bbox[3] = rect->y2 - rect->y1; if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, fontResDict); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, fontResDict); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } } -void AnnotFreeText::draw(Gfx *gfx, GBool printing) { - if (!isVisible (printing)) - return; - - annotLocker(); +Object AnnotFreeText::makeAppearance(XRef* xref) { if (appearance.isNull()) { generateFreeTextAppearance(); } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + return appearance.fetch(xref); } // Before retrieving the res dict, regenerate the appearance stream if needed, // because AnnotFreeText::draw needs to store font info in the res dict Object AnnotFreeText::getAppearanceResDict() { if (appearance.isNull()) { generateFreeTextAppearance(); } return Annot::getAppearanceResDict(); } //------------------------------------------------------------------------ // AnnotLine //------------------------------------------------------------------------ AnnotLine::AnnotLine(PDFDoc *docA, PDFRectangle *rect) : AnnotMarkup(docA, rect) { type = typeLine; annotObj.dictSet ("Subtype", Object(objName, "Line")); @@ -3210,50 +3203,50 @@ void AnnotLine::setCaption(bool new_cap) { caption = new_cap; update ("Cap", Object(new_cap)); invalidateAppearance(); } void AnnotLine::setIntent(AnnotLineIntent new_intent) { const char *intentName; intent = new_intent; if (new_intent == intentLineArrow) intentName = "LineArrow"; else // intentLineDimension intentName = "LineDimension"; update ("IT", Object(objName, intentName)); } void AnnotLine::generateLineAppearance() { double borderWidth, ca = opacity; - appearBBox = new AnnotAppearanceBBox(rect); + AnnotAppearanceBBox appearBBox(getRectFromAnnotObj()); AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) { appearBuilder.setDrawColor(color, gFalse); } appearBuilder.setLineStyleForBorder(border); borderWidth = border->getWidth(); - appearBBox->setBorderWidth(std::max(1., borderWidth)); + appearBBox.setBorderWidth(std::max(1., borderWidth)); const double x1 = coord1->getX(); const double y1 = coord1->getY(); const double x2 = coord2->getX(); const double y2 = coord2->getY(); // Main segment length const double main_len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); // Main segment becomes positive x direction, coord1 becomes (0,0) Matrix matr; const double angle = atan2(y2 - y1, x2 - x1); matr.m[0] = matr.m[3] = cos(angle); matr.m[1] = sin(angle); matr.m[2] = -matr.m[1]; matr.m[4] = x1-rect->x1; matr.m[5] = y1-rect->y1; double tx, ty, captionwidth = 0, captionheight = 0; AnnotLineCaptionPos actualCaptionPos = captionPos; @@ -3276,155 +3269,142 @@ void AnnotLine::generateLineAppearance() layoutText(contents, &out, &i, font, &linewidth, 0, nullptr, gFalse); linewidth *= fontsize; if (linewidth > captionwidth) { captionwidth = linewidth; } ++lines; } captionheight = lines * fontsize; // If text is longer than available space, turn into captionPosTop if (captionwidth > captionmaxwidth) { actualCaptionPos = captionPosTop; } } else { fontResDict = nullptr; font = nullptr; } // Draw main segment matr.transform (0, leaderLineLength, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); if (captionwidth != 0 && actualCaptionPos == captionPosInline) { // Break in the middle matr.transform ((main_len-captionwidth)/2 - captionhmargin, leaderLineLength, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} l S\n", tx, ty); matr.transform ((main_len+captionwidth)/2 + captionhmargin, leaderLineLength, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", tx, ty); } matr.transform (main_len, leaderLineLength, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} l S\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); // TODO: Line endings // Draw caption text if (caption) { double tlx = (main_len - captionwidth) / 2, tly; // Top-left coords if (actualCaptionPos == captionPosInline) { tly = leaderLineLength + captionheight / 2; } else { tly = leaderLineLength + captionheight + 2*borderWidth; } tlx += captionTextHorizontal; tly += captionTextVertical; // Adjust bounding box matr.transform (tlx, tly-captionheight, &tx, &ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (tlx+captionwidth, tly-captionheight, &tx, &ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (tlx+captionwidth, tly, &tx, &ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (tlx, tly, &tx, &ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); // Setup text state (reusing transformed top-left coord) appearBuilder.appendf ("0 g BT /AnnotDrawFont {0:.2f} Tf\n", fontsize); // Font color: black appearBuilder.appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} Tm\n", matr.m[0], matr.m[1], matr.m[2], matr.m[3], tx, ty); appearBuilder.appendf ("0 {0:.2f} Td\n", -fontsize * font->getDescent()); // Draw text int i = 0; double xposPrev = 0; while (i < contents->getLength()) { GooString out; double linewidth, xpos; layoutText(contents, &out, &i, font, &linewidth, 0, nullptr, gFalse); linewidth *= fontsize; xpos = (captionwidth - linewidth) / 2; appearBuilder.appendf("{0:.2f} {1:.2f} Td\n", xpos - xposPrev, -fontsize); appearBuilder.writeString(out); appearBuilder.append ("Tj\n"); xposPrev = xpos; } appearBuilder.append ("ET\n"); font->decRefCnt(); } // Draw leader lines double ll_len = fabs(leaderLineLength) + leaderLineExtension; double sign = leaderLineLength >= 0 ? 1 : -1; if (ll_len != 0) { matr.transform (0, 0, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (0, sign*ll_len, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} l S\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (main_len, 0, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); matr.transform (main_len, sign*ll_len, &tx, &ty); appearBuilder.appendf ("{0:.2f} {1:.2f} l S\n", tx, ty); - appearBBox->extendTo (tx, ty); + appearBBox.extendTo (tx, ty); } appearBuilder.append ("Q\n"); double bbox[4]; - appearBBox->getBBoxRect(bbox); + appearBBox.getBBoxRect(bbox); if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, fontResDict); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, fontResDict); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } + appearBBox.getPageRect(rect); } -void AnnotLine::draw(Gfx *gfx, GBool printing) { - if (!isVisible (printing)) - return; - - annotLocker(); +Object AnnotLine::makeAppearance(XRef* xref) { if (appearance.isNull()) { generateLineAppearance(); } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (appearBBox) { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - appearBBox->getPageXMin(), appearBBox->getPageYMin(), - appearBBox->getPageXMax(), appearBBox->getPageYMax(), - getRotation()); - } else { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - } + return appearance.fetch(xref); } // Before retrieving the res dict, regenerate the appearance stream if needed, // because AnnotLine::draw may need to store font info in the res dict Object AnnotLine::getAppearanceResDict() { if (appearance.isNull()) { generateLineAppearance(); } return Annot::getAppearanceResDict(); } //------------------------------------------------------------------------ // AnnotTextMarkup //------------------------------------------------------------------------ AnnotTextMarkup::AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) : AnnotMarkup(docA, rect) { switch (subType) { case typeHighlight: annotObj.dictSet ("Subtype", Object(objName, "Highlight")); break; @@ -3518,63 +3498,58 @@ void AnnotTextMarkup::setQuadrilaterals(AnnotQuadrilaterals *quadPoints) { Array *a = new Array(xref); for (int i = 0; i < quadPoints->getQuadrilateralsLength(); ++i) { a->add(Object(quadPoints->getX1(i))); a->add(Object(quadPoints->getY1(i))); a->add(Object(quadPoints->getX2(i))); a->add(Object(quadPoints->getY2(i))); a->add(Object(quadPoints->getX3(i))); a->add(Object(quadPoints->getY3(i))); a->add(Object(quadPoints->getX4(i))); a->add(Object(quadPoints->getY4(i))); } delete quadrilaterals; quadrilaterals = new AnnotQuadrilaterals(a, rect); annotObj.dictSet ("QuadPoints", Object(a)); invalidateAppearance(); } -void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) { +Object AnnotTextMarkup::makeAppearance(XRef* xref) { double ca = 1; int i; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull() || type == typeHighlight) { GBool blendMultiply = gTrue; ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); /* Adjust BBox */ - delete appearBBox; - appearBBox = new AnnotAppearanceBBox(rect); + AnnotAppearanceBBox appearBBox(getRectFromAnnotObj()); for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) { - appearBBox->extendTo (quadrilaterals->getX1(i) - rect->x1, quadrilaterals->getY1(i) - rect->y1); - appearBBox->extendTo (quadrilaterals->getX2(i) - rect->x1, quadrilaterals->getY2(i) - rect->y1); - appearBBox->extendTo (quadrilaterals->getX3(i) - rect->x1, quadrilaterals->getY3(i) - rect->y1); - appearBBox->extendTo (quadrilaterals->getX4(i) - rect->x1, quadrilaterals->getY4(i) - rect->y1); + appearBBox.extendTo (quadrilaterals->getX1(i) - rect->x1, quadrilaterals->getY1(i) - rect->y1); + appearBBox.extendTo (quadrilaterals->getX2(i) - rect->x1, quadrilaterals->getY2(i) - rect->y1); + appearBBox.extendTo (quadrilaterals->getX3(i) - rect->x1, quadrilaterals->getY3(i) - rect->y1); + appearBBox.extendTo (quadrilaterals->getX4(i) - rect->x1, quadrilaterals->getY4(i) - rect->y1); } switch (type) { case typeUnderline: if (color) { appearBuilder.setDrawColor(color, gFalse); } appearBuilder.append ("[] 0 d 1 w\n"); for (i = 0; i < quadrilaterals->getQuadrilateralsLength(); ++i) { double x3, y3, x4, y4; x3 = quadrilaterals->getX3(i); y3 = quadrilaterals->getY3(i); x4 = quadrilaterals->getX4(i); y4 = quadrilaterals->getY4(i); appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", x3, y3); appearBuilder.appendf ("{0:.2f} {1:.2f} l\n", x4, y4); appearBuilder.append ("S\n"); @@ -3647,102 +3622,98 @@ void AnnotTextMarkup::draw(Gfx *gfx, GBool printing) { x2 = quadrilaterals->getX2(i); y2 = quadrilaterals->getY2(i); x3 = quadrilaterals->getX3(i); y3 = quadrilaterals->getY3(i); x4 = quadrilaterals->getX4(i); y4 = quadrilaterals->getY4(i); h4 = fabs(y1 - y3) / 4.0; if (h4 > biggestBorder) { biggestBorder = h4; } appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", x3, y3); appearBuilder.appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x3 - h4, y3 + h4, x1 - h4, y1 - h4, x1, y1); appearBuilder.appendf ("{0:.2f} {1:.2f} l\n", x2, y2); appearBuilder.appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x2 + h4, y2 - h4, x4 + h4, y4 + h4, x4, y4); appearBuilder.append ("f\n"); } - appearBBox->setBorderWidth(biggestBorder); + appearBBox.setBorderWidth(biggestBorder); break; } appearBuilder.append ("Q\n"); double bbox[4]; - bbox[0] = appearBBox->getPageXMin(); - bbox[1] = appearBBox->getPageYMin(); - bbox[2] = appearBBox->getPageXMax(); - bbox[3] = appearBBox->getPageYMax(); + bbox[0] = appearBBox.getPageXMin(); + bbox[1] = appearBBox.getPageYMin(); + bbox[2] = appearBBox.getPageXMax(); + bbox[3] = appearBBox.getPageYMax(); Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", 1, blendMultiply ? "Multiply" : nullptr); if (ca == 1) { appearance = createForm(&appearBuf, bbox, gFalse, resDict); } else { aStream = createForm(&appearBuf, bbox, gTrue, resDict); Dict *resDict2 = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict2); } + appearBBox.getPageRect(rect); } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (appearBBox) { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - appearBBox->getPageXMin(), appearBBox->getPageYMin(), - appearBBox->getPageXMax(), appearBBox->getPageYMax(), - getRotation()); - } else { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - } + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotWidget //------------------------------------------------------------------------ AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj) : Annot(docA, dictObject, obj) { type = typeWidget; field = nullptr; + fontResourceDict = nullptr; initialize(docA, dictObject->getDict()); } AnnotWidget::AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA) : Annot(docA, dictObject, obj) { type = typeWidget; field = fieldA; + fontResourceDict = nullptr; initialize(docA, dictObject->getDict()); } AnnotWidget::~AnnotWidget() { if (appearCharacs) delete appearCharacs; if (action) delete action; + if (fontResourceDict) + delete fontResourceDict; + if (parent) delete parent; } void AnnotWidget::initialize(PDFDoc *docA, Dict *dict) { Object obj1; form = doc->getCatalog()->getForm(); obj1 = dict->lookup("H"); if (obj1.isName()) { const char *modeName = obj1.getName(); if(!strcmp(modeName, "N")) { mode = highlightModeNone; } else if(!strcmp(modeName, "O")) { mode = highlightModeOutline; } else if(!strcmp(modeName, "P") || !strcmp(modeName, "T")) { mode = highlightModePush; } else { @@ -4927,75 +4898,81 @@ void AnnotWidget::updateAppearanceStream() // create a new AP dictionary containing the new appearance stream. // Otherwise, just update the stream we had created previously. if (updatedAppearanceStream.num == -1) { // Write the appearance stream updatedAppearanceStream = xref->addIndirectObject(&obj1); // Write the AP dictionary obj1 = Object(new Dict(xref)); obj1.dictAdd(copyString("N"), Object(updatedAppearanceStream.num, updatedAppearanceStream.gen)); // Update our internal pointers to the appearance dictionary appearStreams = new AnnotAppearance(doc, &obj1); update("AP", std::move(obj1)); } else { // Replace the existing appearance stream xref->setModifiedObject(&obj1, updatedAppearanceStream); } } -void AnnotWidget::draw(Gfx *gfx, GBool printing) { - if (!isVisible (printing)) - return; - - annotLocker(); +Object AnnotWidget::makeAppearance(XRef* xref) { bool addDingbatsResource = false; // Only construct the appearance stream when // - annot doesn't have an AP or // - NeedAppearances is true if (field) { - if (appearance.isNull() || (form && form->getNeedAppearances())) + if (appearance.isNull() || (form && form->getNeedAppearances())) { generateFieldAppearance(&addDingbatsResource); + } } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (addDingbatsResource) { + if (addDingbatsResource && !fontResourceDict) { // We are forcing ZaDb but the font does not exist // so create a fake one - Dict *fontDict = new Dict(gfx->getXRef()); + Dict *fontDict = new Dict(xref); fontDict->add(copyString("BaseFont"), Object(objName, "ZapfDingbats")); fontDict->add(copyString("Subtype"), Object(objName, "Type1")); - Dict *fontsDict = new Dict(gfx->getXRef()); + Dict *fontsDict = new Dict(xref); fontsDict->add(copyString("ZaDb"), Object(fontDict)); - Dict *dict = new Dict(gfx->getXRef()); - dict->add(copyString("Font"), Object(fontsDict)); - gfx->pushResources(dict); - delete dict; + fontResourceDict = new Dict(xref); + fontResourceDict->add(copyString("Font"), Object(fontsDict)); + } else if (!addDingbatsResource && fontResourceDict) { + // Appearance has changed, fake font not required any longer. Cleanup. + delete fontResourceDict; + fontResourceDict = nullptr; } - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - if (addDingbatsResource) { + + return appearance.fetch(xref); +} + +void AnnotWidget::drawAppearance(Gfx *gfx, Object& obj) { + if (fontResourceDict != nullptr) { + gfx->pushResources(fontResourceDict); + } + + Annot::drawAppearance(gfx, obj); + + if (fontResourceDict != nullptr) { gfx->popResources(); } } //------------------------------------------------------------------------ // AnnotMovie //------------------------------------------------------------------------ AnnotMovie::AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA) : Annot(docA, rect) { type = typeMovie; annotObj.dictSet ("Subtype", Object(objName, "Movie")); movie = movieA->copy(); // TODO: create movie dict from movieA initialize(docA, annotObj.getDict()); } AnnotMovie::AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj) : @@ -5022,116 +4999,109 @@ void AnnotMovie::initialize(PDFDoc *docA, Dict* dict) { Object movieDict = dict->lookup("Movie"); if (movieDict.isDict()) { Object obj2 = dict->lookup("A"); if (obj2.isDict()) movie = new Movie (&movieDict, &obj2); else movie = new Movie (&movieDict); if (!movie->isOk()) { delete movie; movie = nullptr; ok = gFalse; } } else { error(errSyntaxError, -1, "Bad Annot Movie"); movie = nullptr; ok = gFalse; } } -void AnnotMovie::draw(Gfx *gfx, GBool printing) { - if (!isVisible (printing)) - return; - - annotLocker(); +Object AnnotMovie::makeAppearance(XRef* xref) { if (appearance.isNull() && movie->getShowPoster()) { int width, height; Object poster = movie->getPoster(); movie->getAspect(&width, &height); if (width != -1 && height != -1 && !poster.isNone()) { GooString *appearBuf = new GooString (); appearBuf->append ("q\n"); appearBuf->appendf ("{0:d} 0 0 {1:d} 0 0 cm\n", width, height); appearBuf->append ("/MImg Do\n"); appearBuf->append ("Q\n"); - Dict *imgDict = new Dict(gfx->getXRef()); + Dict *imgDict = new Dict(xref); imgDict->set("MImg", std::move(poster)); - Dict *resDict = new Dict(gfx->getXRef()); + Dict *resDict = new Dict(xref); resDict->set("XObject", Object(imgDict)); - Dict *formDict = new Dict(gfx->getXRef()); + Dict *formDict = new Dict(xref); formDict->set("Length", Object(appearBuf->getLength())); formDict->set("Subtype", Object(objName, "Form")); formDict->set("Name", Object(objName, "FRM")); - Array *bboxArray = new Array(gfx->getXRef()); + Array *bboxArray = new Array(xref); bboxArray->add(Object(0)); bboxArray->add(Object(0)); bboxArray->add(Object(width)); bboxArray->add(Object(height)); formDict->set("BBox", Object(bboxArray)); - Array *matrix = new Array(gfx->getXRef()); + Array *matrix = new Array(xref); matrix->add(Object(1)); matrix->add(Object(0)); matrix->add(Object(0)); matrix->add(Object(1)); matrix->add(Object(-width / 2)); matrix->add(Object(-height / 2)); formDict->set("Matrix", Object(matrix)); formDict->set("Resources", Object(resDict)); Stream *mStream = new AutoFreeMemStream(copyString(appearBuf->getCString()), 0, appearBuf->getLength(), Object(formDict)); delete appearBuf; - Dict *dict = new Dict(gfx->getXRef()); + Dict *dict = new Dict(xref); dict->set("FRM", Object(mStream)); - Dict *resDict2 = new Dict(gfx->getXRef()); + Dict *resDict2 = new Dict(xref); resDict2->set("XObject", Object(dict)); appearBuf = new GooString (); appearBuf->append ("q\n"); appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height); appearBuf->append ("q\n"); appearBuf->appendf ("0 0 {0:d} {1:d} re W n\n", width, height); appearBuf->appendf ("1 0 0 1 {0:d} {1:d} cm\n", width / 2, height / 2); appearBuf->append ("/FRM Do\n"); appearBuf->append ("Q\n"); appearBuf->append ("Q\n"); double bbox[4]; bbox[0] = bbox[1] = 0; bbox[2] = width; bbox[3] = height; appearance = createForm(appearBuf, bbox, gFalse, resDict2); delete appearBuf; } } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotScreen //------------------------------------------------------------------------ AnnotScreen::AnnotScreen(PDFDoc *docA, PDFRectangle *rect) : Annot(docA, rect) { type = typeScreen; annotObj.dictSet ("Subtype", Object(objName, "Screen")); initialize(docA, annotObj.getDict()); } AnnotScreen::AnnotScreen(PDFDoc *docA, Object *dictObject, Object *obj) : Annot(docA, dictObject, obj) { type = typeScreen; initialize(docA, dictObject->getDict()); } AnnotScreen::~AnnotScreen() { @@ -5310,47 +5280,43 @@ void AnnotGeometry::setType(AnnotSubtype new_type) { } type = new_type; update("Subtype", Object(objName, typeName)); invalidateAppearance(); } void AnnotGeometry::setInteriorColor(AnnotColor *new_color) { delete interiorColor; if (new_color) { Object obj1 = new_color->writeToObject(xref); update ("IC", std::move(obj1)); interiorColor = new_color; } else { interiorColor = nullptr; } invalidateAppearance(); } -void AnnotGeometry::draw(Gfx *gfx, GBool printing) { +Object AnnotGeometry::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) appearBuilder.setDrawColor(color, gFalse); double borderWidth = border->getWidth(); appearBuilder.setLineStyleForBorder(border); if (interiorColor) appearBuilder.setDrawColor(interiorColor, gTrue); if (type == typeSquare) { appearBuilder.appendf ("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n", borderWidth / 2.0, borderWidth / 2.0, (rect->x2 - rect->x1) - borderWidth, (rect->y2 - rect->y1) - borderWidth); } else { @@ -5406,44 +5372,41 @@ void AnnotGeometry::draw(Gfx *gfx, GBool printing) { else appearBuilder.append ("S\n"); appearBuilder.append ("Q\n"); double bbox[4]; bbox[0] = bbox[1] = 0; bbox[2] = rect->x2 - rect->x1; bbox[3] = rect->y2 - rect->y1; if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotPolygon //------------------------------------------------------------------------ AnnotPolygon::AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType) : AnnotMarkup(docA, rect) { switch (subType) { case typePolygon: annotObj.dictSet ("Subtype", Object(objName, "Polygon")); break; case typePolyLine: annotObj.dictSet ("Subtype", Object(objName, "PolyLine")); break; default: assert (0 && "Invalid subtype for AnnotGeometry\n"); } // Store dummy path with one null vertex only Array *a = new Array(doc->getXRef()); @@ -5604,111 +5567,98 @@ void AnnotPolygon::setInteriorColor(AnnotColor *new_color) { interiorColor = new_color; } else { interiorColor = nullptr; } invalidateAppearance(); } void AnnotPolygon::setIntent(AnnotPolygonIntent new_intent) { const char *intentName; intent = new_intent; if (new_intent == polygonCloud) intentName = "PolygonCloud"; else if (new_intent == polylineDimension) intentName = "PolyLineDimension"; else // polygonDimension intentName = "PolygonDimension"; update ("IT", Object(objName, intentName)); } -void AnnotPolygon::draw(Gfx *gfx, GBool printing) { +Object AnnotPolygon::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { - appearBBox = new AnnotAppearanceBBox(rect); + AnnotAppearanceBBox appearBBox(getRectFromAnnotObj()); ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) { appearBuilder.setDrawColor(color, gFalse); } appearBuilder.setLineStyleForBorder(border); - appearBBox->setBorderWidth(std::max(1., border->getWidth())); + appearBBox.setBorderWidth(std::max(1., border->getWidth())); if (interiorColor) { appearBuilder.setDrawColor(interiorColor, gTrue); } if (vertices->getCoordsLength() != 0) { appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1); - appearBBox->extendTo (vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1); + appearBBox.extendTo (vertices->getX(0) - rect->x1, vertices->getY(0) - rect->y1); for (int i = 1; i < vertices->getCoordsLength(); ++i) { appearBuilder.appendf ("{0:.2f} {1:.2f} l\n", vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1); - appearBBox->extendTo (vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1); + appearBBox.extendTo (vertices->getX(i) - rect->x1, vertices->getY(i) - rect->y1); } if (type == typePolygon) { if (interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent) { appearBuilder.append ("b\n"); } else { appearBuilder.append ("s\n"); } } else { appearBuilder.append ("S\n"); } } appearBuilder.append ("Q\n"); double bbox[4]; - appearBBox->getBBoxRect(bbox); + appearBBox.getBBoxRect(bbox); if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } + appearBBox.getPageRect(rect); } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (appearBBox) { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - appearBBox->getPageXMin(), appearBBox->getPageYMin(), - appearBBox->getPageXMax(), appearBBox->getPageYMax(), - getRotation()); - } else { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - } + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotCaret //------------------------------------------------------------------------ AnnotCaret::AnnotCaret(PDFDoc *docA, PDFRectangle *rect) : AnnotMarkup(docA, rect) { type = typeCaret; annotObj.dictSet ("Subtype", Object(objName, "Caret")); initialize(docA, annotObj.getDict()); } AnnotCaret::AnnotCaret(PDFDoc *docA, Object *dictObject, Object *obj) : AnnotMarkup(docA, dictObject, obj) { type = typeCaret; initialize(docA, dictObject->getDict()); } AnnotCaret::~AnnotCaret() { @@ -5820,102 +5770,89 @@ void AnnotInk::parseInkList(Array *array) { void AnnotInk::freeInkList() { if (inkList) { for (int i = 0; i < inkListLength; ++i) delete inkList[i]; gfree(inkList); } } void AnnotInk::setInkList(AnnotPath **paths, int n_paths) { freeInkList(); Array *a = new Array(xref); writeInkList(paths, n_paths, a); parseInkList(a); annotObj.dictSet ("InkList", Object(a)); invalidateAppearance(); } -void AnnotInk::draw(Gfx *gfx, GBool printing) { +Object AnnotInk::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { - appearBBox = new AnnotAppearanceBBox(rect); + AnnotAppearanceBBox appearBBox(getRectFromAnnotObj()); ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) { appearBuilder.setDrawColor(color, gFalse); } appearBuilder.setLineStyleForBorder(border); - appearBBox->setBorderWidth(std::max(1., border->getWidth())); + appearBBox.setBorderWidth(std::max(1., border->getWidth())); for (int i = 0; i < inkListLength; ++i) { const AnnotPath * path = inkList[i]; if (path && path->getCoordsLength() != 0) { appearBuilder.appendf ("{0:.2f} {1:.2f} m\n", path->getX(0) - rect->x1, path->getY(0) - rect->y1); - appearBBox->extendTo (path->getX(0) - rect->x1, path->getY(0) - rect->y1); + appearBBox.extendTo (path->getX(0) - rect->x1, path->getY(0) - rect->y1); for (int j = 1; j < path->getCoordsLength(); ++j) { appearBuilder.appendf ("{0:.2f} {1:.2f} l\n", path->getX(j) - rect->x1, path->getY(j) - rect->y1); - appearBBox->extendTo (path->getX(j) - rect->x1, path->getY(j) - rect->y1); + appearBBox.extendTo (path->getX(j) - rect->x1, path->getY(j) - rect->y1); } appearBuilder.append ("S\n"); } } appearBuilder.append ("Q\n"); double bbox[4]; - appearBBox->getBBoxRect(bbox); + appearBBox.getBBoxRect(bbox); if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } + appearBBox.getPageRect(rect); } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - if (appearBBox) { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - appearBBox->getPageXMin(), appearBBox->getPageYMin(), - appearBBox->getPageXMax(), appearBBox->getPageYMax(), - getRotation()); - } else { - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); - } + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotFileAttachment //------------------------------------------------------------------------ AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename) : AnnotMarkup(docA, rect) { type = typeFileAttachment; annotObj.dictSet("Subtype", Object(objName, "FileAttachment")); annotObj.dictSet("FS", Object(filename->copy())); initialize(docA, annotObj.getDict()); } AnnotFileAttachment::AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj) : AnnotMarkup(docA, dictObject, obj) { type = typeFileAttachment; initialize(docA, dictObject->getDict()); } @@ -6038,85 +5975,78 @@ void AnnotFileAttachment::initialize(PDFDoc *docA, Dict* dict) { "0.533333 0.541176 0.521569 RG 1 w\n" \ "0 j\n" \ "11.949 13.184 m 16.191 8.941 l S\n" \ "0.729412 0.741176 0.713725 RG 11.949 14.184 m 16.191 9.941 l S\n" \ "0.533333 0.541176 0.521569 RG 14.07 6.82 m 9.828 11.062 l S\n" \ "0.729412 0.741176 0.713725 RG 14.07 7.82 m 9.828 12.062 l S\n" \ "0.533333 0.541176 0.521569 RG 6.93 15.141 m 8 20 14.27 20.5 16 20.5 c\n" \ "18.094 20.504 19.5 20 19.5 18 c 19.5 16.699 20.91 16.418 22.5 16.5 c S\n" \ "0.729412 0.741176 0.713725 RG 0.999781 w\n" \ "1 j\n" \ "q 1 0 0 -1 0 24 cm\n" \ "8.492 7.707 m 8.492 8.535 7.82 9.207 6.992 9.207 c 6.164 9.207 5.492\n" \ "8.535 5.492 7.707 c 5.492 6.879 6.164 6.207 6.992 6.207 c 7.82 6.207\n" \ "8.492 6.879 8.492 7.707 c h\n" \ "8.492 7.707 m S Q\n" \ "1 w\n" \ "0 j\n" \ "6.93 16.141 m 8 21 14.27 21.5 16 21.5 c 18.094 21.504 19.5 21 19.5 19 c\n" \ "19.5 17.699 20.91 17.418 22.5 17.5 c S\n" -void AnnotFileAttachment::draw(Gfx *gfx, GBool printing) { +Object AnnotFileAttachment::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) appearBuilder.setDrawColor(color, gTrue); else appearBuilder.append ("1 1 1 rg\n"); if (!name->cmp("PushPin")) appearBuilder.append (ANNOT_FILE_ATTACHMENT_AP_PUSHPIN); else if (!name->cmp("Paperclip")) appearBuilder.append (ANNOT_FILE_ATTACHMENT_AP_PAPERCLIP); else if (!name->cmp("Graph")) appearBuilder.append (ANNOT_FILE_ATTACHMENT_AP_GRAPH); else if (!name->cmp("Tag")) appearBuilder.append (ANNOT_FILE_ATTACHMENT_AP_TAG); appearBuilder.append ("Q\n"); double bbox[4]; bbox[0] = bbox[1] = 0; bbox[2] = bbox[3] = 24; if (ca == 1) { appearance = createForm (appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm (appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } } - // draw the appearance stream - Object obj = appearance.fetch(gfx->getXRef()); - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + return appearance.fetch(xref); } //------------------------------------------------------------------------ // AnnotSound //------------------------------------------------------------------------ AnnotSound::AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA) : AnnotMarkup(docA, rect) { type = typeSound; annotObj.dictSet ("Subtype", Object(objName, "Sound")); annotObj.dictSet ("Sound", soundA->getObject()->copy()); initialize(docA, annotObj.getDict()); } AnnotSound::AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj) : AnnotMarkup(docA, dictObject, obj) { type = typeSound; initialize(docA, dictObject->getDict()); } @@ -6190,82 +6120,74 @@ void AnnotSound::initialize(PDFDoc *docA, Dict* dict) { "17.5 14.5 m 17.5 11.973 l 17.5 8.941 15.047 6.5 12 6.5 c 8.953 6.5 6.5\n" \ "8.941 6.5 11.973 c 6.5 14.5 l S\n" \ "2 w\n" \ "0 J\n" \ "12 6.52 m 12 3 l S\n" \ "1 J\n" \ "8 3 m 16 3 l S\n" \ "0.729412 0.741176 0.713725 RG 12 21 m 12 21 l 13.656 21 15 19.656 15 18 c\n" \ "15 14 l 15 12.344 13.656 11 12 11 c 12 11 l 10.344 11 9 12.344 9 14 c\n" \ "9 18 l 9 19.656 10.344 21 12 21 c h\n" \ "12 21 m S\n" \ "1 w\n" \ "17.5 15.5 m 17.5 12.973 l 17.5 9.941 15.047 7.5 12 7.5 c 8.953 7.5 6.5\n" \ "9.941 6.5 12.973 c 6.5 15.5 l S\n" \ "2 w\n" \ "0 J\n" \ "12 7.52 m 12 4 l S\n" \ "1 J\n" \ "8 4 m 16 4 l S\n" -void AnnotSound::draw(Gfx *gfx, GBool printing) { - Object obj; +Object AnnotSound::makeAppearance(XRef* xref) { double ca = 1; - if (!isVisible (printing)) - return; - - annotLocker(); if (appearance.isNull()) { ca = opacity; AnnotAppearanceBuilder appearBuilder; appearBuilder.append ("q\n"); if (color) appearBuilder.setDrawColor(color, gTrue); else appearBuilder.append ("1 1 1 rg\n"); if (!name->cmp("Speaker")) appearBuilder.append (ANNOT_SOUND_AP_SPEAKER); else if (!name->cmp("Mic")) appearBuilder.append (ANNOT_SOUND_AP_MIC); appearBuilder.append ("Q\n"); double bbox[4]; bbox[0] = bbox[1] = 0; bbox[2] = bbox[3] = 24; if (ca == 1) { appearance = createForm(appearBuilder.buffer(), bbox, gFalse, nullptr); } else { Object aStream = createForm(appearBuilder.buffer(), bbox, gTrue, nullptr); GooString appearBuf("/GS0 gs\n/Fm0 Do"); Dict *resDict = createResourcesDict("Fm0", std::move(aStream), "GS0", ca, nullptr); appearance = createForm(&appearBuf, bbox, gFalse, resDict); } } - // draw the appearance stream - obj = appearance.fetch(gfx->getXRef()); - gfx->drawAnnot(&obj, (AnnotBorder *)nullptr, color, - rect->x1, rect->y1, rect->x2, rect->y2, getRotation()); + return appearance.fetch(xref); } //------------------------------------------------------------------------ // Annot3D //------------------------------------------------------------------------ Annot3D::Annot3D(PDFDoc *docA, PDFRectangle *rect) : Annot(docA, rect) { type = type3D; annotObj.dictSet ("Subtype", Object(objName, "3D")); initialize(docA, annotObj.getDict()); } Annot3D::Annot3D(PDFDoc *docA, Object *dictObject, Object *obj) : Annot(docA, dictObject, obj) { type = type3D; initialize(docA, dictObject->getDict()); } diff --git poppler/Annot.h poppler/Annot.h index c1acc065..7590357a 100644 --- poppler/Annot.h +++ poppler/Annot.h @@ -461,47 +461,48 @@ protected: int rotation; // R (Default 0) AnnotColor *borderColor; // BC AnnotColor *backColor; // BG GooString *normalCaption; // CA GooString *rolloverCaption; // RC GooString *alternateCaption; // AC // I // RI // IX AnnotIconFit *iconFit; // IF AnnotAppearanceCharacsTextPos position; // TP (Default 0) }; //------------------------------------------------------------------------ // AnnotAppearanceBBox //------------------------------------------------------------------------ class AnnotAppearanceBBox { public: - AnnotAppearanceBBox(PDFRectangle *init); + AnnotAppearanceBBox(const PDFRectangle& rect); void setBorderWidth(double w) { borderWidth = w; } // The following functions operate on coords relative to [origX origY] void extendTo(double x, double y); void getBBoxRect(double bbox[4]) const; + void getPageRect(PDFRectangle* rect) const; // Get boundaries in page coordinates double getPageXMin() const; double getPageYMin() const; double getPageXMax() const; double getPageYMax() const; private: double origX, origY, borderWidth; double minX, minY, maxX, maxY; }; //------------------------------------------------------------------------ // AnnotAppearanceBuilder //------------------------------------------------------------------------ class AnnotAppearanceBuilder { public: AnnotAppearanceBuilder(); ~AnnotAppearanceBuilder(); @@ -606,41 +607,42 @@ public: actionPageClosing, ///< Performed when the page containing the annotation is closed actionPageVisible, ///< Performed when the page containing the annotation becomes visible actionPageInvisible ///< Performed when the page containing the annotation becomes invisible }; enum FormAdditionalActionsType { actionFieldModified, ///< Performed when the when the user modifies the field actionFormatField, ///< Performed before the field is formatted to display its value actionValidateField, ///< Performed when the field value changes actionCalculateField, ///< Performed when the field needs to be recalculated }; Annot(PDFDoc *docA, PDFRectangle *rectA); Annot(PDFDoc *docA, Object *dictObject); Annot(PDFDoc *docA, Object *dictObject, Object *obj); GBool isOk() { return ok; } void incRefCnt(); void decRefCnt(); - virtual void draw(Gfx *gfx, GBool printing); + void draw(Gfx *gfx, GBool printing); + // Get the resource dict of the appearance stream virtual Object getAppearanceResDict(); GBool match(Ref *refA) { return ref.num == refA->num && ref.gen == refA->gen; } double getXMin(); double getYMin(); double getXMax(); double getYMax(); double getFontSize() { return fontSize; } void setRect(PDFRectangle *rect); void setRect(double x1, double y1, double x2, double y2); // Sets the annot contents to new_content // new_content should never be NULL virtual void setContents(GooString *new_content); void setName(GooString *new_name); @@ -677,71 +679,74 @@ public: int getId() { return ref.num; } // Check if point is inside the annot rectangle. GBool inRect(double x, double y) const; static void layoutText(const GooString *text, GooString *outBuf, int *i, const GfxFont *font, double *width, double widthLimit, int *charCount, GBool noReencode); private: void readArrayNum(Object *pdfArray, int key, double *value); // write vStr[i:j[ in appearBuf void initialize (PDFDoc *docA, Dict *dict); void setPage (int new_page, GBool updateP); // Called by Page::addAnnot and Annots ctor protected: virtual ~Annot(); virtual void removeReferencedObjects(); // Called by Page::removeAnnot + virtual Object makeAppearance(XRef* xref); + virtual void drawAppearance(Gfx *gfx, Object& obj); + + PDFRectangle getRectFromAnnotObj() const; Object createForm(const GooString *appearBuf, double *bbox, GBool transparencyGroup, Dict *resDict); Dict *createResourcesDict(const char *formName, Object &&formStream, const char *stateName, double opacity, const char *blendMode); GBool isVisible(GBool printing); int getRotation() const; // Updates the field key of the annotation dictionary // and sets M to the current time void update(const char *key, Object &&value); // Delete appearance streams and reset appearance state void invalidateAppearance(); Object annotObj; int refCnt; // required data AnnotSubtype type; // Annotation type PDFRectangle *rect; // Rect // optional data GooString *contents; // Contents GooString *name; // NM GooString *modified; // M int page; // P Guint flags; // F (must be a 32 bit unsigned int) AnnotAppearance *appearStreams; // AP Object appearance; // a reference to the Form XObject stream // for the normal appearance - AnnotAppearanceBBox *appearBBox; // BBox of generated appearance GooString *appearState; // AS int treeKey; // Struct Parent; Object oc; // OC PDFDoc *doc; XRef *xref; // the xref table for this PDF file Ref ref; // object ref identifying this annotation AnnotBorder *border; // Border, BS AnnotColor *color; // C double fontSize; GBool ok; bool hasRef; #ifdef MULTITHREADED GooMutex mutex; #endif }; //------------------------------------------------------------------------ // AnnotPopup @@ -824,81 +829,81 @@ private: class AnnotText: public AnnotMarkup { public: enum AnnotTextState { stateUnknown, // Marked state model stateMarked, // Marked stateUnmarked, // Unmarked // Review state model stateAccepted, // Accepted stateRejected, // Rejected stateCancelled, // Cancelled stateCompleted, // Completed stateNone // None }; AnnotText(PDFDoc *docA, PDFRectangle *rect); AnnotText(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotText(); - void draw(Gfx *gfx, GBool printing) override; - // getters GBool getOpen() const { return open; } const GooString *getIcon() const { return icon; } AnnotTextState getState() const { return state; } void setOpen(GBool openA); void setIcon(GooString *new_icon); private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + GBool open; // Open (Default false) GooString *icon; // Name (Default Note) AnnotTextState state; // State (Default Umarked if // StateModel Marked // None if StareModel Review) }; //------------------------------------------------------------------------ // AnnotMovie //------------------------------------------------------------------------ class AnnotMovie: public Annot { public: AnnotMovie(PDFDoc *docA, PDFRectangle *rect, Movie *movieA); AnnotMovie(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotMovie(); - void draw(Gfx *gfx, GBool printing) override; - const GooString* getTitle() const { return title; } Movie* getMovie() { return movie; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + GooString* title; // T Movie* movie; // Movie + A }; //------------------------------------------------------------------------ // AnnotScreen //------------------------------------------------------------------------ class AnnotScreen: public Annot { public: AnnotScreen(PDFDoc *docA, PDFRectangle *rect); AnnotScreen(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotScreen(); const GooString* getTitle() const { return title; } AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; } LinkAction* getAction() { return action; } // The caller should now delete the result @@ -917,103 +922,106 @@ class AnnotScreen: public Annot { }; //------------------------------------------------------------------------ // AnnotLink //------------------------------------------------------------------------ class AnnotLink: public Annot { public: enum AnnotLinkEffect { effectNone, // N effectInvert, // I effectOutline, // O effectPush // P }; AnnotLink(PDFDoc *docA, PDFRectangle *rect); AnnotLink(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotLink(); - void draw(Gfx *gfx, GBool printing) override; - // getters LinkAction *getAction() const { return action; } AnnotLinkEffect getLinkEffect() const { return linkEffect; } Dict *getUriAction() const { return uriAction; } AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; } protected: void initialize(PDFDoc *docA, Dict *dict); + void drawAppearance(Gfx *gfx, Object& obj) override; + LinkAction *action; // A, Dest AnnotLinkEffect linkEffect; // H (Default I) Dict *uriAction; // PA AnnotQuadrilaterals *quadrilaterals; // QuadPoints }; //------------------------------------------------------------------------ // AnnotFreeText //------------------------------------------------------------------------ class AnnotFreeText: public AnnotMarkup { public: enum AnnotFreeTextQuadding { quaddingLeftJustified, // 0 quaddingCentered, // 1 quaddingRightJustified // 2 }; enum AnnotFreeTextIntent { intentFreeText, // FreeText intentFreeTextCallout, // FreeTextCallout intentFreeTextTypeWriter // FreeTextTypeWriter }; AnnotFreeText(PDFDoc *docA, PDFRectangle *rect, GooString *da); AnnotFreeText(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotFreeText(); - void draw(Gfx *gfx, GBool printing) override; Object getAppearanceResDict() override; void setContents(GooString *new_content) override; void setAppearanceString(GooString *new_string); void setQuadding(AnnotFreeTextQuadding new_quadding); void setStyleString(GooString *new_string); void setCalloutLine(AnnotCalloutLine *line); void setIntent(AnnotFreeTextIntent new_intent); // getters const GooString *getAppearanceString() const { return appearanceString; } AnnotFreeTextQuadding getQuadding() const { return quadding; } // return rc const GooString *getStyleString() const { return styleString; } AnnotCalloutLine *getCalloutLine() const { return calloutLine; } AnnotFreeTextIntent getIntent() const { return intent; } AnnotBorderEffect *getBorderEffect() const { return borderEffect; } PDFRectangle *getRectangle() const { return rectangle; } AnnotLineEndingStyle getEndStyle() const { return endStyle; } +private: + + Object makeAppearance(XRef* xref) override; + protected: void initialize(PDFDoc *docA, Dict *dict); static void parseAppearanceString(GooString *da, double &fontsize, AnnotColor* &fontcolor); void generateFreeTextAppearance(); // required GooString *appearanceString; // DA // optional AnnotFreeTextQuadding quadding; // Q (Default 0) // RC GooString *styleString; // DS AnnotCalloutLine *calloutLine; // CL AnnotFreeTextIntent intent; // IT AnnotBorderEffect *borderEffect; // BE PDFRectangle *rectangle; // RD // inherited from Annot // AnnotBorderBS border; // BS AnnotLineEndingStyle endStyle; // LE (Default None) @@ -1023,115 +1031,120 @@ protected: // AnnotLine //------------------------------------------------------------------------ class AnnotLine: public AnnotMarkup { public: enum AnnotLineIntent { intentLineArrow, // LineArrow intentLineDimension // LineDimension }; enum AnnotLineCaptionPos { captionPosInline, // Inline captionPosTop // Top }; AnnotLine(PDFDoc *docA, PDFRectangle *rect); AnnotLine(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotLine(); - void draw(Gfx *gfx, GBool printing) override; Object getAppearanceResDict() override; void setContents(GooString *new_content) override; void setVertices(double x1, double y1, double x2, double y2); void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end); void setInteriorColor(AnnotColor *new_color); void setLeaderLineLength(double len); void setLeaderLineExtension(double len); void setCaption(bool new_cap); void setIntent(AnnotLineIntent new_intent); // getters AnnotLineEndingStyle getStartStyle() const { return startStyle; } AnnotLineEndingStyle getEndStyle() const { return endStyle; } AnnotColor *getInteriorColor() const { return interiorColor; } double getLeaderLineLength() const { return leaderLineLength; } double getLeaderLineExtension() const { return leaderLineExtension; } bool getCaption() const { return caption; } AnnotLineIntent getIntent() const { return intent; } double getLeaderLineOffset() const { return leaderLineOffset; } AnnotLineCaptionPos getCaptionPos() const { return captionPos; } Dict *getMeasure() const { return measure; } double getCaptionTextHorizontal() const { return captionTextHorizontal; } double getCaptionTextVertical() const { return captionTextVertical; } double getX1() const { return coord1->getX(); } double getY1() const { return coord1->getY(); } double getX2() const { return coord2->getX(); } double getY2() const { return coord2->getY(); } +private: + + Object makeAppearance(XRef* xref) override; + protected: void initialize(PDFDoc *docA, Dict *dict); void generateLineAppearance(); // required AnnotCoord *coord1, *coord2; // optional // inherited from Annot // AnnotBorderBS border; // BS AnnotLineEndingStyle startStyle; // LE (Default [/None /None]) AnnotLineEndingStyle endStyle; // AnnotColor *interiorColor; // IC double leaderLineLength; // LL (Default 0) double leaderLineExtension; // LLE (Default 0) bool caption; // Cap (Default false) AnnotLineIntent intent; // IT double leaderLineOffset; // LLO AnnotLineCaptionPos captionPos; // CP (Default Inline) Dict *measure; // Measure double captionTextHorizontal; // CO (Default [0, 0]) double captionTextVertical; // }; //------------------------------------------------------------------------ // AnnotTextMarkup //------------------------------------------------------------------------ class AnnotTextMarkup: public AnnotMarkup { public: AnnotTextMarkup(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); AnnotTextMarkup(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotTextMarkup(); - void draw(Gfx *gfx, GBool printing) override; - // typeHighlight, typeUnderline, typeSquiggly or typeStrikeOut void setType(AnnotSubtype new_type); void setQuadrilaterals(AnnotQuadrilaterals *quadPoints); AnnotQuadrilaterals *getQuadrilaterals() const { return quadrilaterals; } +private: + + Object makeAppearance(XRef* xref) override; + protected: void initialize(PDFDoc *docA, Dict *dict); AnnotQuadrilaterals *quadrilaterals; // QuadPoints }; //------------------------------------------------------------------------ // AnnotStamp //------------------------------------------------------------------------ class AnnotStamp: public AnnotMarkup { public: AnnotStamp(PDFDoc *docA, PDFRectangle *rect); AnnotStamp(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotStamp(); void setIcon(GooString *new_icon); @@ -1139,96 +1152,96 @@ public: const GooString *getIcon() const { return icon; } private: void initialize(PDFDoc *docA, Dict *dict); GooString *icon; // Name (Default Draft) }; //------------------------------------------------------------------------ // AnnotGeometry //------------------------------------------------------------------------ class AnnotGeometry: public AnnotMarkup { public: AnnotGeometry(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); AnnotGeometry(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotGeometry(); - void draw(Gfx *gfx, GBool printing) override; - void setType(AnnotSubtype new_type); // typeSquare or typeCircle void setInteriorColor(AnnotColor *new_color); // getters AnnotColor *getInteriorColor() const { return interiorColor; } AnnotBorderEffect *getBorderEffect() const { return borderEffect; } PDFRectangle *getGeometryRect() const { return geometryRect; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + AnnotColor *interiorColor; // IC AnnotBorderEffect *borderEffect; // BE PDFRectangle *geometryRect; // RD (combined with Rect) }; //------------------------------------------------------------------------ // AnnotPolygon //------------------------------------------------------------------------ class AnnotPolygon: public AnnotMarkup { public: enum AnnotPolygonIntent { polygonCloud, // PolygonCloud polylineDimension, // PolyLineDimension polygonDimension // PolygonDimension }; AnnotPolygon(PDFDoc *docA, PDFRectangle *rect, AnnotSubtype subType); AnnotPolygon(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotPolygon(); - void draw(Gfx *gfx, GBool printing) override; - void setType(AnnotSubtype new_type); // typePolygon or typePolyLine void setVertices(AnnotPath *path); void setStartEndStyle(AnnotLineEndingStyle start, AnnotLineEndingStyle end); void setInteriorColor(AnnotColor *new_color); void setIntent(AnnotPolygonIntent new_intent); // getters AnnotPath *getVertices() const { return vertices; } AnnotLineEndingStyle getStartStyle() const { return startStyle; } AnnotLineEndingStyle getEndStyle() const { return endStyle; } AnnotColor *getInteriorColor() const { return interiorColor; } AnnotBorderEffect *getBorderEffect() const { return borderEffect; } AnnotPolygonIntent getIntent() const { return intent; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + // required AnnotPath *vertices; // Vertices // optional AnnotLineEndingStyle startStyle; // LE (Default [/None /None]) AnnotLineEndingStyle endStyle; // // inherited from Annot // AnnotBorderBS border; // BS AnnotColor *interiorColor; // IC AnnotBorderEffect *borderEffect; // BE AnnotPolygonIntent intent; // IT // Measure }; //------------------------------------------------------------------------ // AnnotCaret //------------------------------------------------------------------------ class AnnotCaret: public AnnotMarkup { public: @@ -1250,164 +1263,166 @@ public: private: void initialize(PDFDoc *docA, Dict *dict); AnnotCaretSymbol symbol; // Sy (Default None) PDFRectangle *caretRect; // RD (combined with Rect) }; //------------------------------------------------------------------------ // AnnotInk //------------------------------------------------------------------------ class AnnotInk: public AnnotMarkup { public: AnnotInk(PDFDoc *docA, PDFRectangle *rect); AnnotInk(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotInk(); - void draw(Gfx *gfx, GBool printing) override; - void setInkList(AnnotPath **paths, int n_paths); // getters AnnotPath **getInkList() const { return inkList; } int getInkListLength() const { return inkListLength; } private: void initialize(PDFDoc *docA, Dict *dict); void writeInkList(AnnotPath **paths, int n_paths, Array *dest_array); void parseInkList(Array *src_array); void freeInkList(); + Object makeAppearance(XRef* xref) override; + // required AnnotPath **inkList; // InkList int inkListLength; // optional // inherited from Annot // AnnotBorderBS border; // BS }; //------------------------------------------------------------------------ // AnnotFileAttachment //------------------------------------------------------------------------ class AnnotFileAttachment: public AnnotMarkup { public: AnnotFileAttachment(PDFDoc *docA, PDFRectangle *rect, GooString *filename); AnnotFileAttachment(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotFileAttachment(); - void draw(Gfx *gfx, GBool printing) override; - // getters Object *getFile() { return &file; } const GooString *getName() const { return name; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + // required Object file; // FS // optional GooString *name; // Name }; //------------------------------------------------------------------------ // AnnotSound //------------------------------------------------------------------------ class AnnotSound: public AnnotMarkup { public: AnnotSound(PDFDoc *docA, PDFRectangle *rect, Sound *soundA); AnnotSound(PDFDoc *docA, Object *dictObject, Object *obj); ~AnnotSound(); - void draw(Gfx *gfx, GBool printing) override; - // getters Sound *getSound() { return sound; } const GooString *getName() const { return name; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + // required Sound *sound; // Sound // optional GooString *name; // Name }; //------------------------------------------------------------------------ // AnnotWidget //------------------------------------------------------------------------ class AnnotWidget: public Annot { public: enum AnnotWidgetHighlightMode { highlightModeNone, // N highlightModeInvert, // I highlightModeOutline, // O highlightModePush // P,T }; AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj); AnnotWidget(PDFDoc *docA, Object *dictObject, Object *obj, FormField *fieldA); ~AnnotWidget(); - void draw(Gfx *gfx, GBool printing) override; - void generateFieldAppearance (bool *addDingbatsResource); void updateAppearanceStream (); AnnotWidgetHighlightMode getMode() { return mode; } AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; } LinkAction *getAction() { return action; } // The caller should not delete the result LinkAction *getAdditionalAction(AdditionalActionsType type); // The caller should delete the result LinkAction *getFormAdditionalAction(FormAdditionalActionsType type); // The caller should delete the result Dict *getParent() { return parent; } private: void initialize(PDFDoc *docA, Dict *dict); + Object makeAppearance(XRef* xref) override; + void drawAppearance(Gfx *gfx, Object& obj) override; + Form *form; FormField *field; // FormField object for this annotation AnnotWidgetHighlightMode mode; // H (Default I) AnnotAppearanceCharacs *appearCharacs; // MK LinkAction *action; // A Object additionalActions; // AA // inherited from Annot // AnnotBorderBS border; // BS Dict *parent; // Parent Ref updatedAppearanceStream; // {-1,-1} if updateAppearanceStream has never been called + Dict *fontResourceDict; // a fake resource, may be required by AnnotAppearanceBuilder::drawText }; //------------------------------------------------------------------------ // Annot3D //------------------------------------------------------------------------ class Annot3D: public Annot { class Activation { public: enum ActivationATrigger { aTriggerUnknown, aTriggerPageOpened, // PO aTriggerPageVisible, // PV aTriggerUserAction // XA }; enum ActivationAState { aStateUnknown, aStateEnabled, // I aStateDisabled // L