filter/source/pdf/pdfexport.cxx | 30 + starmath/inc/document.hxx | 4 starmath/inc/view.hxx | 19 - starmath/source/document.cxx | 309 ++++++++++++++++++++ starmath/source/unomodel.cxx | 37 +- starmath/source/view.cxx | 317 --------------------- sw/qa/extras/htmlexport/data/embedded_formula.fodt | 30 + sw/qa/extras/htmlexport/htmlexport.cxx | 66 ++-- sw/source/filter/html/htmlplug.cxx | 184 +++++++----- sw/source/filter/html/wrthtml.cxx | 6 sw/source/filter/html/wrthtml.hxx | 3 11 files changed, 563 insertions(+), 442 deletions(-)
New commits: commit cc539b1c2f3db9f868ad1c3b4292c8454ac5a79d Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Oct 30 17:14:47 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Oct 31 12:00:47 2023 +0300 ReqIF: introduce ExportFormulasAsPDF HTML export filter option Change-Id: Id400bd5571d0a192d854620abe83d862e0512434 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158663 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/htmlexport/data/embedded_formula.fodt b/sw/qa/extras/htmlexport/data/embedded_formula.fodt new file mode 100644 index 000000000000..46e5391223c0 --- /dev/null +++ b/sw/qa/extras/htmlexport/data/embedded_formula.fodt @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:body> + <office:text> + <text:p>Formula:</text:p> + <text:p><draw:frame draw:name="Formula1" text:anchor-type="as-char" svg:width="1.549cm" svg:height="0.531cm"><draw:object> + <math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> + <semantics> + <mrow> + <msup> + <mi mathvariant="normal">e</mi> + <mrow> + <mi>i</mi> + <mi>π</mi> + </mrow> + </msup> + <mo stretchy="false">+</mo> + <mn>1</mn> + <mo stretchy="false">=</mo> + <mn>0</mn> + </mrow> + <annotation encoding="StarMath 5.0">{ func e ^ { i %pi } + 1 } = 0</annotation> + </semantics> + </math> + </draw:object> + </draw:frame></text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 7c74a27161ee..6b8de215d27c 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -13,6 +13,7 @@ #include <string_view> #include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/io/XActiveDataStreamer.hpp> #include <com/sun/star/io/XSeekable.hpp> @@ -265,9 +266,10 @@ public: { } + OUString GetObjectPath(const OUString& ext); /// Get the .ole path, assuming maTempFile is an XHTML export result. - OUString GetOlePath(); - OUString GetPngPath(); + OUString GetOlePath() { return GetObjectPath(".ole"); } + OUString GetPngPath() { return GetObjectPath(".png"); } /// Parse the ole1 data out of an RTF fragment URL. void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1); /// Export using the C++ HTML export filter, with xhtmlns=reqif-xhtml. @@ -276,35 +278,19 @@ public: void ImportFromReqif(const OUString& rUrl); }; -OUString SwHtmlDomExportTest::GetOlePath() +OUString SwHtmlDomExportTest::GetObjectPath(const OUString& ext) { + assert(ext.startsWith(".")); SvMemoryStream aStream; WrapReqifFromTempFile(aStream); xmlDocUniquePtr pDoc = parseXmlStream(&aStream); CPPUNIT_ASSERT(pDoc); OUString aOlePath = getXPath( pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data"); - OUString aOleSuffix(".ole"); - CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix)); + CPPUNIT_ASSERT(aOlePath.endsWith(ext)); INetURLObject aUrl(maTempFile.GetURL()); - aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - aOleSuffix.getLength())); - aUrl.setExtension(u"ole"); - return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE); -} - -OUString SwHtmlDomExportTest::GetPngPath() -{ - SvMemoryStream aStream; - WrapReqifFromTempFile(aStream); - xmlDocUniquePtr pDoc = parseXmlStream(&aStream); - CPPUNIT_ASSERT(pDoc); - OUString aPngPath = getXPath( - pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data"); - OUString aPngSuffix(".png"); - CPPUNIT_ASSERT(aPngPath.endsWith(aPngSuffix)); - INetURLObject aUrl(maTempFile.GetURL()); - aUrl.setBase(aPngPath.subView(0, aPngPath.getLength() - aPngSuffix.getLength())); - aUrl.setExtension(u"png"); + aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - ext.getLength())); + aUrl.setExtension(ext.subView(1)); return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE); } @@ -2830,6 +2816,40 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_PreserveSpaces) CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString()); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ExportFormulasAsPDF) +{ + // Given a document with a formula: + createSwDoc("embedded_formula.fodt"); + + // When exporting to reqif with ExportFormulasAsPDF=true: + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY_THROW); + uno::Sequence<beans::PropertyValue> aStoreProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + comphelper::makePropertyValue("ExportFormulasAsPDF", true), + }; + xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); + + // Make sure that the formula is exported as PDF: + SvMemoryStream aStream; + WrapReqifFromTempFile(aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[2]/reqif-xhtml:object", + "type", "application/pdf"); + + css::uno::Sequence<css::beans::PropertyValue> descr{ + comphelper::makePropertyValue("URL", GetObjectPath(".pdf")), + }; + + uno::Reference<lang::XMultiServiceFactory> xFactory( + comphelper::getProcessComponentContext()->getServiceManager(), uno::UNO_QUERY_THROW); + uno::Reference<document::XTypeDetection> xTypeDetection( + xFactory->createInstance("com.sun.star.document.TypeDetection"), uno::UNO_QUERY_THROW); + + CPPUNIT_ASSERT_EQUAL(OUString("pdf_Portable_Document_Format"), + xTypeDetection->queryTypeByDescriptor(descr, true)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx index c4131e1af4f9..31722b3ed47f 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -1483,6 +1483,119 @@ Writer& OutHTML_FrameFormatOLENode( Writer& rWrt, const SwFrameFormat& rFrameFor return rWrt; } +static void OutHTMLGraphic(SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, SwOLENode* pOLENd, + const Graphic& rGraphic, bool bObjectOpened, bool bInCntnr) +{ + OUString aGraphicURL; + OUString aMimeType; + if (!rWrt.mbEmbedImages) + { + const OUString* pTempFileName = rWrt.GetOrigFileName(); + if (pTempFileName) + aGraphicURL = *pTempFileName; + + OUString aFilterName("JPG"); + XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible; + + if (bObjectOpened) + { + aFilterName = "PNG"; + nFlags = XOutFlags::NONE; + aMimeType = "image/png"; + + if (rGraphic.GetType() == GraphicType::NONE) + { + // The OLE Object has no replacement image, write a stub. + aGraphicURL = lcl_CalculateFileName(rWrt.GetOrigFileName(), rGraphic, u"png"); + osl::File aFile(aGraphicURL); + aFile.open(osl_File_OpenFlag_Create); + aFile.close(); + } + } + + ErrCode nErr = XOutBitmap::WriteGraphic(rGraphic, aGraphicURL, aFilterName, nFlags); + if (nErr) // error, don't write anything + { + rWrt.m_nWarn = WARN_SWG_POOR_LOAD; + if (bObjectOpened) // Still at least close the tag. + rWrt.Strm().WriteOString( + Concat2View("</" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">")); + return; + } + aGraphicURL = URIHelper::SmartRel2Abs(INetURLObject(rWrt.GetBaseURL()), aGraphicURL, + URIHelper::GetMaybeFileHdl()); + } + HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask : HtmlFrmOpts::GenImgMask; + if (bObjectOpened) + nFlags |= HtmlFrmOpts::Replacement; + HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace); + OutHTML_ImageStart(aHtml, rWrt, rFrameFormat, aGraphicURL, rGraphic, pOLENd->GetTitle(), + pOLENd->GetTwipSize(), nFlags, "ole", nullptr, aMimeType); + OutHTML_ImageEnd(aHtml, rWrt); +} + +static void OutHTMLStartObject(SwHTMLWriter& rWrt, const OUString& rFileName, const OUString& rFileType) +{ + OUString aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), rFileName); + + if (rWrt.IsLFPossible()) + rWrt.OutNewLine(); + rWrt.Strm().WriteOString( + Concat2View("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object)); + rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + "\"")); + if (!rFileType.isEmpty()) + rWrt.Strm().WriteOString(Concat2View(" type=\"" + rFileType.toUtf8() + "\"")); + rWrt.Strm().WriteOString(">"); + rWrt.SetLFPossible(true); +} + +static void OutHTMLEndObject(SwHTMLWriter& rWrt) +{ + rWrt.Strm().WriteOString( + Concat2View("</" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object ">")); +} + +static bool TrySaveFormulaAsPDF(SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat, + SwOLENode* pOLENd, bool bWriteReplacementGraphic, bool bInCntnr) +{ + if (!rWrt.mbReqIF) + return false; + if (!rWrt.m_bExportFormulasAsPDF) + return false; + + auto xTextContent = SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + *rWrt.m_pDoc, const_cast<SwFrameFormat*>(&rFrameFormat)); + uno::Reference<frame::XStorable> xStorable(xTextContent->getEmbeddedObject(), uno::UNO_QUERY); + uno::Reference<lang::XServiceInfo> xServiceInfo(xStorable, uno::UNO_QUERY); + if (!xServiceInfo) + return false; + if (!xServiceInfo->supportsService("com.sun.star.formula.FormulaProperties")) + return false; + + Graphic aGraphic(xTextContent->getReplacementGraphic()); + OUString aFileName = lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"pdf"); + + utl::MediaDescriptor aDescr; + aDescr["FilterName"] <<= OUString("math_pdf_Export"); + // Properties from starmath/inc/unomodel.hxx + aDescr["FilterData"] <<= comphelper::InitPropertySequence({ + { u"TitleRow", css::uno::Any(false) }, + { u"FormulaText", css::uno::Any(false) }, + { u"Border", css::uno::Any(false) }, + { u"PrintFormat", css::uno::Any(sal_Int32(1)) }, // PRINT_SIZE_SCALED + }); + xStorable->storeToURL(aFileName, aDescr.getAsConstPropertyValueList()); + + OutHTMLStartObject(rWrt, aFileName, "application/pdf"); + + if (bWriteReplacementGraphic) + OutHTMLGraphic(rWrt, rFrameFormat, pOLENd, aGraphic, true, bInCntnr); + + OutHTMLEndObject(rWrt); + + return true; +} + Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrameFormat, bool bInCntnr, bool bWriteReplacementGraphic ) { @@ -1543,6 +1656,9 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame return rWrt; } + if (TrySaveFormulaAsPDF(rHTMLWrt, rFrameFormat, pOLENd, bWriteReplacementGraphic, bInCntnr)) + return rWrt; + if ( !pOLENd->GetGraphic() ) { SAL_WARN("sw.html", "Unexpected missing OLE fallback graphic"); @@ -1640,80 +1756,18 @@ Writer& OutHTML_FrameFormatOLENodeGrf( Writer& rWrt, const SwFrameFormat& rFrame aFileType = aRTFType; } } - aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aFileName); // Refer to this data. - if (rHTMLWrt.IsLFPossible()) - rHTMLWrt.OutNewLine(); - rWrt.Strm().WriteOString(Concat2View("<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object)); - rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + "\"")); - if (!aFileType.isEmpty()) - rWrt.Strm().WriteOString(Concat2View(" type=\"" + aFileType.toUtf8() + "\"")); - rWrt.Strm().WriteOString(">"); + OutHTMLStartObject(rHTMLWrt, aFileName, aFileType); bObjectOpened = true; - rHTMLWrt.SetLFPossible(true); } if (!bObjectOpened || bWriteReplacementGraphic) - { - OUString aGraphicURL; - OUString aMimeType; - if(!rHTMLWrt.mbEmbedImages) - { - const OUString* pTempFileName = rHTMLWrt.GetOrigFileName(); - if(pTempFileName) - aGraphicURL = *pTempFileName; - - OUString aFilterName("JPG"); - XOutFlags nFlags = XOutFlags::UseGifIfPossible | XOutFlags::UseNativeIfPossible; - - if (bObjectOpened) - { - aFilterName = "PNG"; - nFlags = XOutFlags::NONE; - aMimeType = "image/png"; - - if (aGraphic.GetType() == GraphicType::NONE) - { - // The OLE Object has no replacement image, write a stub. - aGraphicURL = lcl_CalculateFileName(rHTMLWrt.GetOrigFileName(), aGraphic, u"png"); - osl::File aFile(aGraphicURL); - aFile.open(osl_File_OpenFlag_Create); - aFile.close(); - } - } - - ErrCode nErr = XOutBitmap::WriteGraphic( aGraphic, aGraphicURL, - aFilterName, - nFlags ); - if( nErr ) // error, don't write anything - { - rHTMLWrt.m_nWarn = WARN_SWG_POOR_LOAD; - if (bObjectOpened) // Still at least close the tag. - rWrt.Strm().WriteOString(Concat2View("</" + rHTMLWrt.GetNamespace() - + OOO_STRING_SVTOOLS_HTML_object ">")); - return rWrt; - } - aGraphicURL = URIHelper::SmartRel2Abs( - INetURLObject(rWrt.GetBaseURL()), aGraphicURL, - URIHelper::GetMaybeFileHdl() ); - - } - HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask - : HtmlFrmOpts::GenImgMask; - if (bObjectOpened) - nFlags |= HtmlFrmOpts::Replacement; - HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace); - OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic, - pOLENd->GetTitle(), pOLENd->GetTwipSize(), - nFlags, "ole", nullptr, aMimeType ); - OutHTML_ImageEnd(aHtml, rWrt); - } + OutHTMLGraphic(rHTMLWrt, rFrameFormat, pOLENd, aGraphic, bObjectOpened, bInCntnr); if (bObjectOpened) // Close native data. - rWrt.Strm().WriteOString(Concat2View("</" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object - ">")); + OutHTMLEndObject(rHTMLWrt); return rWrt; } diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx index 03879eb42ff0..48c6f8718665 100644 --- a/sw/source/filter/html/wrthtml.cxx +++ b/sw/source/filter/html/wrthtml.cxx @@ -261,6 +261,12 @@ void SwHTMLWriter::SetupFilterFromPropertyValues( it->second >>= m_bExportImagesAsOLE; } + it = aStoreMap.find("ExportFormulasAsPDF"); + if (it != aStoreMap.end()) + { + it->second >>= m_bExportFormulasAsPDF; + } + it = aStoreMap.find("ShapeDPI"); if (it != aStoreMap.end()) { diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index f8f5a111e6eb..721c901d379b 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -429,6 +429,9 @@ public: /// ReqIF mode: export images as OLE objects. bool m_bExportImagesAsOLE = false; + /// ReqIF mode: export formulas as PDFs. + bool m_bExportFormulasAsPDF = false; + /// DPI used when exporting a vector shape as a bitmap. std::optional<sal_Int32> m_nShapeDPI; commit 9af110d9243309d6260699e51b046a281dc24fc4 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Oct 30 08:41:54 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 23:34:46 2023 +0300 Allow passing Math-specific options to PDF export The options present in the Math' Print dialog: * Contents: - Title; - Formula text; - Borders; * Size: - Original size; - Fit to page; - Scaling N% were previously not handled in math_pdf_Export. This change makes them handled, similar to handling of other modules' options. The final handling of them happens in SmDocShell::Impl_Print. TitleRow (boolean; default = true) FormulaText (boolean; default = true) Border (boolean; default = true) PrintFormat (long: 0 - original size; 1 - fit to page; 2 - scaling to PrintScale; default = 0) PrintScale (unsigned short; default = 100) They are also available in command line, as implemented in commit 0c3b8792b712e939d2ad524d554f96616b4844be (PDF export: allow setting filter data keys from the cmdline, 2022-01-24), using JSON syntax. TODO: make these options available in Math' PDF export dialog. Change-Id: I4fcc609e943823a5325a4840988a96c9d5ab3223 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158637 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx index 338463f184f8..cc9e56983d7f 100644 --- a/filter/source/pdf/pdfexport.cxx +++ b/filter/source/pdf/pdfexport.cxx @@ -451,7 +451,11 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& OUString aOpenPassword, aPermissionPassword; Reference< beans::XMaterialHolder > xEnc; Sequence< beans::NamedValue > aPreparedPermissionPassword; - + std::optional<PropertyValue> oMathTitleRow; + std::optional<PropertyValue> oMathFormulaText; + std::optional<PropertyValue> oMathBorder; + std::optional<PropertyValue> oMathPrintFormat; + std::optional<PropertyValue> oMathPrintScale; // getting the string for the creator OUString aCreator; @@ -659,6 +663,17 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& // Redaction & bitmap related stuff else if ( rProp.Name == "IsRedactMode" ) rProp.Value >>= mbIsRedactMode; + // Math-specific render options + else if (rProp.Name == "TitleRow") + oMathTitleRow = rProp; + else if (rProp.Name == "FormulaText") + oMathFormulaText = rProp; + else if (rProp.Name == "Border") + oMathBorder = rProp; + else if (rProp.Name == "PrintFormat") + oMathPrintFormat = rProp; + else if (rProp.Name == "PrintScale") + oMathPrintScale = rProp; } if (!maSignCertificate.is() && !aSignCertificateSubjectName.isEmpty()) @@ -950,7 +965,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution ); aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest ); - Sequence< PropertyValue > aRenderOptions{ + std::vector<PropertyValue> aRenderOptionsVector{ comphelper::makePropertyValue("RenderDevice", uno::Reference<awt::XDevice>(xDevice)), comphelper::makePropertyValue("ExportNotesPages", false), comphelper::makePropertyValue("IsFirstPage", true), @@ -961,6 +976,17 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& comphelper::makePropertyValue("SinglePageSheets", mbSinglePageSheets), comphelper::makePropertyValue("ExportNotesInMargin", mbExportNotesInMargin) }; + if (oMathTitleRow) + aRenderOptionsVector.push_back(*oMathTitleRow); + if (oMathFormulaText) + aRenderOptionsVector.push_back(*oMathFormulaText); + if (oMathBorder) + aRenderOptionsVector.push_back(*oMathBorder); + if (oMathPrintFormat) + aRenderOptionsVector.push_back(*oMathPrintFormat); + if (oMathPrintScale) + aRenderOptionsVector.push_back(*oMathPrintScale); + Sequence aRenderOptions = comphelper::containerToSequence(aRenderOptionsVector); Any& rExportNotesValue = aRenderOptions.getArray()[ 1 ].Value; if( !aPageRange.isEmpty() || !aSelection.hasValue() ) commit bda2daf7d955e540ee9dca379dbc4e5499d50840 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 16:36:43 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 23:33:17 2023 +0300 tdf#157965: UNO methods are expected to return sizes in mm/100 Commit 9e92a17cb6e03beedeeca40bfc8524c2623d31eb made sm to always use twips; before, it used mm/100 except in LOK. That change broke the size values returned from XRenderable::getRenderer: instead of mm/100, the resulting values were in twips, but handled as mm/100. Set the printer's map mode to use mm/100s explicitly. Also use mm/100s in the call to SvxPaperInfo::GetDefaultPaperSize. Change-Id: Id7cf40d4bc19c92dc54ca03d81f25ba1f6bf25b9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158622 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/unomodel.cxx b/starmath/source/unomodel.cxx index f31d01debcc1..582d8f358760 100644 --- a/starmath/source/unomodel.cxx +++ b/starmath/source/unomodel.cxx @@ -912,12 +912,16 @@ uno::Sequence< beans::PropertyValue > SAL_CALL SmModel::getRenderer( SmPrinterAccess aPrinterAccess( *pDocSh ); Size aPrtPaperSize; if (Printer *pPrinter = aPrinterAccess.GetPrinter()) + { + // tdf#157965: UNO methods are expected to return sizes in mm/100 + pPrinter->SetMapMode(MapMode(MapUnit::Map100thMM)); // reset in SmPrinterAccess dtor aPrtPaperSize = pPrinter->GetPaperSize(); + } // if paper size is 0 (usually if no 'real' printer is found), // guess the paper size if (aPrtPaperSize.IsEmpty()) - aPrtPaperSize = SvxPaperInfo::GetDefaultPaperSize(SmMapUnit()); + aPrtPaperSize = SvxPaperInfo::GetDefaultPaperSize(MapUnit::Map100thMM); awt::Size aPageSize( aPrtPaperSize.Width(), aPrtPaperSize.Height() ); uno::Sequence< beans::PropertyValue > aRenderer(1); commit 2e6f3d2983ec6b44334acfc07c14286afe400269 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 14:48:48 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 23:10:42 2023 +0300 Drop pointless print format limitation of PDF export PRINT_SIZE_NORMAL is the default, so will be used anyway, when export doesn't provide an explicit value. Preventing an explicitly provided value is wrong. Change-Id: I4781f429741f3882cc9c716839763ccddfc07652 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158619 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index c93aa5da1b1d..6bf52577f643 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -1486,9 +1486,6 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin Size aSize(GetSize()); MapMode OutputMapMode; - // PDF export should always use PRINT_SIZE_NORMAL ... - if (!rPrintUIOptions.getBoolValue("IsPrinter")) - ePrintSize = PRINT_SIZE_NORMAL; switch (ePrintSize) { case PRINT_SIZE_NORMAL: commit 3b50aa6b3d251c7ce63e550d1476879e1c2d1de3 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 14:45:01 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 22:49:15 2023 +0300 Only decrase zoom on fit-to-page printout when printing frame Change-Id: I51466924823bc574acfed6cff9fbd1bc4c77931b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158618 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index 4c65fec0b6fa..c93aa5da1b1d 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -1501,7 +1501,7 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin sal_uInt16 nZ = std::min(o3tl::convert(aOutRect.GetWidth(), 100, aSize.Width()), o3tl::convert(aOutRect.GetHeight(), 100, aSize.Height())); - if (nZ > MINZOOM) + if (bIsPrintFrame && nZ > MINZOOM) nZ -= 10; Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100); commit f96ba9e4e10a030b5e8abceafdc0a4c209534595 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 14:59:47 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 22:46:50 2023 +0300 Drop some intermediate conversions to pixel Should improve independence of results from resolution. Some output devices are not even pixel-based (e.g., PDF output). Change-Id: Id4359bfa0d7ba76ac4e4694c3ae4f042a780cd53 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158620 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index 7d2847f9d8f6..4c65fec0b6fa 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -1498,11 +1498,9 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin case PRINT_SIZE_SCALED: if (!aSize.IsEmpty()) { - Size OutputSize(rOutDev.LogicToPixel(aOutRect.GetSize(), MapMode(SmMapUnit()))); - Size GraphicSize(rOutDev.LogicToPixel(aSize, MapMode(SmMapUnit()))); sal_uInt16 nZ - = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()), - o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height())); + = std::min(o3tl::convert(aOutRect.GetWidth(), 100, aSize.Width()), + o3tl::convert(aOutRect.GetHeight(), 100, aSize.Height())); if (nZ > MINZOOM) nZ -= 10; Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100); @@ -1522,14 +1520,13 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin } } - aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode), MapMode(SmMapUnit())); + aSize = OutputDevice::LogicToLogic(aSize, OutputMapMode, MapMode(SmMapUnit())); Point aPos(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2, aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2); - aPos = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(SmMapUnit())), OutputMapMode); - aOutRect - = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(SmMapUnit())), OutputMapMode); + aPos = OutputDevice::LogicToLogic(aPos, MapMode(SmMapUnit()), OutputMapMode); + aOutRect = OutputDevice::LogicToLogic(aOutRect, MapMode(SmMapUnit()), OutputMapMode); rOutDev.SetMapMode(OutputMapMode); rOutDev.SetClipRegion(vcl::Region(aOutRect)); commit c084cc8ec2a768b517a817276826849793932d37 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 16:45:53 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 22:44:36 2023 +0300 Subtraction could wrap Change-Id: Ifc248835a70ee593e47d50bb0e1bf9165eb06391 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158623 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/inc/view.hxx b/starmath/inc/view.hxx index b55edc1715c5..9a98d6d17476 100644 --- a/starmath/inc/view.hxx +++ b/starmath/inc/view.hxx @@ -37,8 +37,8 @@ class SmPrintUIOptions; class SmGraphicAccessible; class SmGraphicWidget; -#define MINZOOM sal_uInt16(25) -#define MAXZOOM sal_uInt16(800) +constexpr sal_uInt16 MINZOOM = 25; +constexpr sal_uInt16 MAXZOOM = 800; class SmGraphicWindow final : public InterimItemWindow { diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index eae45ed3630b..7d2847f9d8f6 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -1503,7 +1503,8 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin sal_uInt16 nZ = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()), o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height())); - nZ -= 10; + if (nZ > MINZOOM) + nZ -= 10; Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100); OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); commit ac4995ced8e5bf0366ddffaff89cadf6e0284e36 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sun Oct 29 14:57:03 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 22:42:31 2023 +0300 tdf#157966: fix "Fit to page" printing option Regression after commit bf4bbc3c2174b21577b8878bc3197923ba44a029 (replace std::max(std::min()) with std::clamp, 2020-11-16). Change-Id: Iada43ba352cbfb5ea597c72c871b47beb2d766c9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158617 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index a5d294f74fe8..eae45ed3630b 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -1504,7 +1504,7 @@ void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrin = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()), o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height())); nZ -= 10; - Fraction aFraction(std::clamp(nZ, MINZOOM, sal_uInt16(100)), 1); + Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100); OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); } commit 7ce30a52ee7c68ee452eaa0d92b1b6cd2612b3ab Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Oct 28 20:23:00 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 22:41:29 2023 +0300 Move Impl_Print from SmViewShell to SmDocShell All functionality is in the latter, anyway. This move allows to exclude dependency on existing views from SmModel::render. Change-Id: I3dff855b7f25089439c8afc57904a25a48fd127b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158594 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/inc/document.hxx b/starmath/inc/document.hxx index 214d9a9ce558..6ad7161ec96d 100644 --- a/starmath/inc/document.hxx +++ b/starmath/inc/document.hxx @@ -61,6 +61,7 @@ inline constexpr OUStringLiteral MATHML_XML = u"MathML XML (Math)"; class SmDocShell; class EditEngine; class SmEditEngine; +class SmPrintUIOptions; class SmPrinterAccess { @@ -221,6 +222,9 @@ public: mathml::SmMlIteratorFree(m_pMlElementTree); m_pMlElementTree = pMlElementTree; } + + void Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrintUIOptions, + tools::Rectangle aOutRect); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/inc/view.hxx b/starmath/inc/view.hxx index 41e28a44c3df..b55edc1715c5 100644 --- a/starmath/inc/view.hxx +++ b/starmath/inc/view.hxx @@ -37,6 +37,9 @@ class SmPrintUIOptions; class SmGraphicAccessible; class SmGraphicWidget; +#define MINZOOM sal_uInt16(25) +#define MAXZOOM sal_uInt16(800) + class SmGraphicWindow final : public InterimItemWindow { private: @@ -258,19 +261,6 @@ class SmViewShell final : public SfxViewShell DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void ); virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; - static Size GetTextLineSize(OutputDevice const & rDevice, - const OUString& rLine); - static Size GetTextSize(OutputDevice const & rDevice, - std::u16string_view rText, - tools::Long MaxWidth); - static void DrawTextLine(OutputDevice& rDevice, - const Point& rPosition, - const OUString& rLine); - static void DrawText(OutputDevice& rDevice, - const Point& rPosition, - std::u16string_view rText, - sal_uInt16 MaxWidth); - virtual SfxPrinter *GetPrinter(bool bCreate = false) override; virtual sal_uInt16 SetPrinter(SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL) override; @@ -334,9 +324,6 @@ public: void Execute( SfxRequest& rReq ); void GetState(SfxItemSet &); - void Impl_Print( OutputDevice &rOutDev, const SmPrintUIOptions &rPrintUIOptions, - tools::Rectangle aOutRect ); - /** Set bInsertIntoEditWindow so we know where to insert * * This method is called whenever SmGraphicWidget or SmEditWindow gets focus, diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx index e7c5dee90c4d..a5d294f74fe8 100644 --- a/starmath/source/document.cxx +++ b/starmath/source/document.cxx @@ -24,6 +24,7 @@ #include <comphelper/fileformat.h> #include <comphelper/accessibletexthelper.hxx> +#include <comphelper/string.hxx> #include <rtl/ustrbuf.hxx> #include <rtl/ustring.hxx> #include <sal/log.hxx> @@ -1224,4 +1225,317 @@ bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium ) return aEquation.ConvertFromStarMath( rMedium ); } +static Size GetTextLineSize(OutputDevice const& rDevice, const OUString& rLine) +{ + Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight()); + const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8; + + if (nTabPos) + { + aSize.setWidth(0); + sal_Int32 nPos = 0; + do + { + if (nPos > 0) + aSize.setWidth(((aSize.Width() / nTabPos) + 1) * nTabPos); + + const OUString aText = rLine.getToken(0, '\t', nPos); + aSize.AdjustWidth(rDevice.GetTextWidth(aText)); + } while (nPos >= 0); + } + + return aSize; +} + +static Size GetTextSize(OutputDevice const& rDevice, std::u16string_view rText, + tools::Long MaxWidth) +{ + Size aSize; + Size aTextSize; + if (rText.empty()) + return aTextSize; + + sal_Int32 nPos = 0; + do + { + OUString aLine(o3tl::getToken(rText, 0, '\n', nPos)); + aLine = aLine.replaceAll("\r", ""); + + aSize = GetTextLineSize(rDevice, aLine); + + if (aSize.Width() > MaxWidth) + { + do + { + OUString aText; + sal_Int32 m = aLine.getLength(); + sal_Int32 nLen = m; + + for (sal_Int32 n = 0; n < nLen; n++) + { + sal_Unicode cLineChar = aLine[n]; + if ((cLineChar == ' ') || (cLineChar == '\t')) + { + aText = aLine.copy(0, n); + if (GetTextLineSize(rDevice, aText).Width() < MaxWidth) + m = n; + else + break; + } + } + + aText = aLine.copy(0, m); + aLine = aLine.replaceAt(0, m, u""); + aSize = GetTextLineSize(rDevice, aText); + aTextSize.AdjustHeight(aSize.Height()); + aTextSize.setWidth(std::clamp(aSize.Width(), aTextSize.Width(), MaxWidth)); + + aLine = comphelper::string::stripStart(aLine, ' '); + aLine = comphelper::string::stripStart(aLine, '\t'); + aLine = comphelper::string::stripStart(aLine, ' '); + } while (!aLine.isEmpty()); + } + else + { + aTextSize.AdjustHeight(aSize.Height()); + aTextSize.setWidth(std::max(aTextSize.Width(), aSize.Width())); + } + } while (nPos >= 0); + + return aTextSize; +} + +static void DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine) +{ + Point aPoint(rPosition); + const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8; + + if (nTabPos) + { + sal_Int32 nPos = 0; + do + { + if (nPos > 0) + aPoint.setX(((aPoint.X() / nTabPos) + 1) * nTabPos); + + OUString aText = rLine.getToken(0, '\t', nPos); + rDevice.DrawText(aPoint, aText); + aPoint.AdjustX(rDevice.GetTextWidth(aText)); + } while (nPos >= 0); + } + else + rDevice.DrawText(aPoint, rLine); +} + +static void DrawText(OutputDevice& rDevice, const Point& rPosition, std::u16string_view rText, + sal_uInt16 MaxWidth) +{ + if (rText.empty()) + return; + + Point aPoint(rPosition); + Size aSize; + + sal_Int32 nPos = 0; + do + { + OUString aLine(o3tl::getToken(rText, 0, '\n', nPos)); + aLine = aLine.replaceAll("\r", ""); + aSize = GetTextLineSize(rDevice, aLine); + if (aSize.Width() > MaxWidth) + { + do + { + OUString aText; + sal_Int32 m = aLine.getLength(); + sal_Int32 nLen = m; + + for (sal_Int32 n = 0; n < nLen; n++) + { + sal_Unicode cLineChar = aLine[n]; + if ((cLineChar == ' ') || (cLineChar == '\t')) + { + aText = aLine.copy(0, n); + if (GetTextLineSize(rDevice, aText).Width() < MaxWidth) + m = n; + else + break; + } + } + aText = aLine.copy(0, m); + aLine = aLine.replaceAt(0, m, u""); + + DrawTextLine(rDevice, aPoint, aText); + aPoint.AdjustY(aSize.Height()); + + aLine = comphelper::string::stripStart(aLine, ' '); + aLine = comphelper::string::stripStart(aLine, '\t'); + aLine = comphelper::string::stripStart(aLine, ' '); + } while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth); + + // print the remaining text + if (!aLine.isEmpty()) + { + DrawTextLine(rDevice, aPoint, aLine); + aPoint.AdjustY(aSize.Height()); + } + } + else + { + DrawTextLine(rDevice, aPoint, aLine); + aPoint.AdjustY(aSize.Height()); + } + } while (nPos >= 0); +} + +void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrintUIOptions, + tools::Rectangle aOutRect) +{ + const bool bIsPrintTitle = rPrintUIOptions.getBoolValue(PRTUIOPT_TITLE_ROW, true); + const bool bIsPrintFrame = rPrintUIOptions.getBoolValue(PRTUIOPT_BORDER, true); + const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue(PRTUIOPT_FORMULA_TEXT, true); + SmPrintSize ePrintSize(static_cast<SmPrintSize>( + rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL))); + const sal_uInt16 nZoomFactor + = static_cast<sal_uInt16>(rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_SCALE, 100)); + + rOutDev.Push(); + rOutDev.SetLineColor(COL_BLACK); + + // output text on top + if (bIsPrintTitle) + { + Size aSize600(0, 600); + Size aSize650(0, 650); + vcl::Font aFont(FAMILY_DONTKNOW, aSize600); + + aFont.SetAlignment(ALIGN_TOP); + aFont.SetWeight(WEIGHT_BOLD); + aFont.SetFontSize(aSize650); + aFont.SetColor(COL_BLACK); + rOutDev.SetFont(aFont); + + Size aTitleSize(GetTextSize(rOutDev, GetTitle(), aOutRect.GetWidth() - 200)); + + aFont.SetWeight(WEIGHT_NORMAL); + aFont.SetFontSize(aSize600); + rOutDev.SetFont(aFont); + + Size aDescSize(GetTextSize(rOutDev, GetComment(), aOutRect.GetWidth() - 200)); + + if (bIsPrintFrame) + rOutDev.DrawRect(tools::Rectangle( + aOutRect.TopLeft(), Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200 + + aDescSize.Height() + 100))); + aOutRect.AdjustTop(200); + + // output title + aFont.SetWeight(WEIGHT_BOLD); + aFont.SetFontSize(aSize650); + rOutDev.SetFont(aFont); + Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2, + aOutRect.Top()); + DrawText(rOutDev, aPoint, GetTitle(), + sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200)); + aOutRect.AdjustTop(aTitleSize.Height() + 200); + + // output description + aFont.SetWeight(WEIGHT_NORMAL); + aFont.SetFontSize(aSize600); + rOutDev.SetFont(aFont); + aPoint.setX(aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2); + aPoint.setY(aOutRect.Top()); + DrawText(rOutDev, aPoint, GetComment(), + sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200)); + aOutRect.AdjustTop(aDescSize.Height() + 300); + } + + // output text on bottom + if (bIsPrintFormulaText) + { + vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600)); + aFont.SetAlignment(ALIGN_TOP); + aFont.SetColor(COL_BLACK); + + // get size + rOutDev.SetFont(aFont); + + Size aSize(GetTextSize(rOutDev, GetText(), aOutRect.GetWidth() - 200)); + + aOutRect.AdjustBottom(-(aSize.Height() + 600)); + + if (bIsPrintFrame) + rOutDev.DrawRect(tools::Rectangle( + aOutRect.BottomLeft(), Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200))); + + Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2, + aOutRect.Bottom() + 300); + DrawText(rOutDev, aPoint, GetText(), + sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200)); + aOutRect.AdjustBottom(-200); + } + + if (bIsPrintFrame) + rOutDev.DrawRect(aOutRect); + + aOutRect.AdjustTop(100); + aOutRect.AdjustLeft(100); + aOutRect.AdjustBottom(-100); + aOutRect.AdjustRight(-100); + + Size aSize(GetSize()); + + MapMode OutputMapMode; + // PDF export should always use PRINT_SIZE_NORMAL ... + if (!rPrintUIOptions.getBoolValue("IsPrinter")) + ePrintSize = PRINT_SIZE_NORMAL; + switch (ePrintSize) + { + case PRINT_SIZE_NORMAL: + OutputMapMode = MapMode(SmMapUnit()); + break; + + case PRINT_SIZE_SCALED: + if (!aSize.IsEmpty()) + { + Size OutputSize(rOutDev.LogicToPixel(aOutRect.GetSize(), MapMode(SmMapUnit()))); + Size GraphicSize(rOutDev.LogicToPixel(aSize, MapMode(SmMapUnit()))); + sal_uInt16 nZ + = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()), + o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height())); + nZ -= 10; + Fraction aFraction(std::clamp(nZ, MINZOOM, sal_uInt16(100)), 1); + + OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); + } + else + OutputMapMode = MapMode(SmMapUnit()); + break; + + case PRINT_SIZE_ZOOMED: + { + Fraction aFraction(nZoomFactor, 100); + + OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); + break; + } + } + + aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode), MapMode(SmMapUnit())); + + Point aPos(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2, + aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2); + + aPos = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(SmMapUnit())), OutputMapMode); + aOutRect + = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(SmMapUnit())), OutputMapMode); + + rOutDev.SetMapMode(OutputMapMode); + rOutDev.SetClipRegion(vcl::Region(aOutRect)); + DrawFormula(rOutDev, aPos); + rOutDev.SetClipRegion(); + + rOutDev.Pop(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/starmath/source/unomodel.cxx b/starmath/source/unomodel.cxx index 89796c27e04f..f31d01debcc1 100644 --- a/starmath/source/unomodel.cxx +++ b/starmath/source/unomodel.cxx @@ -970,17 +970,6 @@ void SAL_CALL SmModel::render( if (xModel != pDocSh->GetModel()) return; - //!! when called via API we may not have an active view - //!! thus we go and look for a view that can be used. - SfxViewShell* pViewSh = SfxViewShell::GetFirst( false /* search non-visible views as well*/, checkSfxViewShell<SmViewShell> ); - while (pViewSh && pViewSh->GetObjectShell() != pDocSh) - pViewSh = SfxViewShell::GetNext( *pViewSh, false /* search non-visible views as well*/, checkSfxViewShell<SmViewShell> ); - SmViewShell *pView = dynamic_cast< SmViewShell *>( pViewSh ); - SAL_WARN_IF( !pView, "starmath", "SmModel::render : no SmViewShell found" ); - - if (!pView) - return; - SmPrinterAccess aPrinterAccess( *pDocSh ); Size aPrtPaperSize; @@ -1024,7 +1013,7 @@ void SAL_CALL SmModel::render( m_pPrintUIOptions.reset(new SmPrintUIOptions); m_pPrintUIOptions->processProperties( rxOptions ); - pView->Impl_Print( *pOut, *m_pPrintUIOptions, OutputRect ); + pDocSh->Impl_Print(*pOut, *m_pPrintUIOptions, OutputRect); // release SmPrintUIOptions when everything is done. // That way, when SmPrintUIOptions is needed again it will read the latest configuration settings in its c-tor. diff --git a/starmath/source/view.cxx b/starmath/source/view.cxx index bdc8b0729335..29db2fc3c45a 100644 --- a/starmath/source/view.cxx +++ b/starmath/source/view.cxx @@ -89,9 +89,6 @@ #include <ElementsDockingWindow.hxx> #include <helpids.h> -#define MINZOOM sal_uInt16(25) -#define MAXZOOM sal_uInt16(800) - // space around the edit window, in pixels // fdo#69111: Increased border on the top so that the window is // easier to tear off. @@ -1192,320 +1189,6 @@ void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY ) SfxViewShell::SetZoomFactor( rX, rY ); } -Size SmViewShell::GetTextLineSize(OutputDevice const & rDevice, const OUString& rLine) -{ - Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight()); - const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8; - - if (nTabPos) - { - aSize.setWidth( 0 ); - sal_Int32 nPos = 0; - do - { - if (nPos > 0) - aSize.setWidth( ((aSize.Width() / nTabPos) + 1) * nTabPos ); - - const OUString aText = rLine.getToken(0, '\t', nPos); - aSize.AdjustWidth(rDevice.GetTextWidth(aText) ); - } - while (nPos >= 0); - } - - return aSize; -} - -Size SmViewShell::GetTextSize(OutputDevice const & rDevice, std::u16string_view rText, tools::Long MaxWidth) -{ - Size aSize; - Size aTextSize; - if (rText.empty()) - return aTextSize; - - sal_Int32 nPos = 0; - do - { - OUString aLine( o3tl::getToken(rText, 0, '\n', nPos) ); - aLine = aLine.replaceAll("\r", ""); - - aSize = GetTextLineSize(rDevice, aLine); - - if (aSize.Width() > MaxWidth) - { - do - { - OUString aText; - sal_Int32 m = aLine.getLength(); - sal_Int32 nLen = m; - - for (sal_Int32 n = 0; n < nLen; n++) - { - sal_Unicode cLineChar = aLine[n]; - if ((cLineChar == ' ') || (cLineChar == '\t')) - { - aText = aLine.copy(0, n); - if (GetTextLineSize(rDevice, aText).Width() < MaxWidth) - m = n; - else - break; - } - } - - aText = aLine.copy(0, m); - aLine = aLine.replaceAt(0, m, u""); - aSize = GetTextLineSize(rDevice, aText); - aTextSize.AdjustHeight(aSize.Height() ); - aTextSize.setWidth( std::clamp(aSize.Width(), aTextSize.Width(), MaxWidth) ); - - aLine = comphelper::string::stripStart(aLine, ' '); - aLine = comphelper::string::stripStart(aLine, '\t'); - aLine = comphelper::string::stripStart(aLine, ' '); - } - while (!aLine.isEmpty()); - } - else - { - aTextSize.AdjustHeight(aSize.Height() ); - aTextSize.setWidth( std::max(aTextSize.Width(), aSize.Width()) ); - } - } - while (nPos >= 0); - - return aTextSize; -} - -void SmViewShell::DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine) -{ - Point aPoint(rPosition); - const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8; - - if (nTabPos) - { - sal_Int32 nPos = 0; - do - { - if (nPos > 0) - aPoint.setX( ((aPoint.X() / nTabPos) + 1) * nTabPos ); - - OUString aText = rLine.getToken(0, '\t', nPos); - rDevice.DrawText(aPoint, aText); - aPoint.AdjustX(rDevice.GetTextWidth(aText) ); - } - while ( nPos >= 0 ); - } - else - rDevice.DrawText(aPoint, rLine); -} - -void SmViewShell::DrawText(OutputDevice& rDevice, const Point& rPosition, std::u16string_view rText, sal_uInt16 MaxWidth) -{ - if (rText.empty()) - return; - - Point aPoint(rPosition); - Size aSize; - - sal_Int32 nPos = 0; - do - { - OUString aLine( o3tl::getToken(rText, 0, '\n', nPos) ); - aLine = aLine.replaceAll("\r", ""); - aSize = GetTextLineSize(rDevice, aLine); - if (aSize.Width() > MaxWidth) - { - do - { - OUString aText; - sal_Int32 m = aLine.getLength(); - sal_Int32 nLen = m; - - for (sal_Int32 n = 0; n < nLen; n++) - { - sal_Unicode cLineChar = aLine[n]; - if ((cLineChar == ' ') || (cLineChar == '\t')) - { - aText = aLine.copy(0, n); - if (GetTextLineSize(rDevice, aText).Width() < MaxWidth) - m = n; - else - break; - } - } - aText = aLine.copy(0, m); - aLine = aLine.replaceAt(0, m, u""); - - DrawTextLine(rDevice, aPoint, aText); - aPoint.AdjustY(aSize.Height() ); - - aLine = comphelper::string::stripStart(aLine, ' '); - aLine = comphelper::string::stripStart(aLine, '\t'); - aLine = comphelper::string::stripStart(aLine, ' '); - } - while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth); - - // print the remaining text - if (!aLine.isEmpty()) - { - DrawTextLine(rDevice, aPoint, aLine); - aPoint.AdjustY(aSize.Height() ); - } - } - else - { - DrawTextLine(rDevice, aPoint, aLine); - aPoint.AdjustY(aSize.Height() ); - } - } - while ( nPos >= 0 ); -} - -void SmViewShell::Impl_Print(OutputDevice &rOutDev, const SmPrintUIOptions &rPrintUIOptions, tools::Rectangle aOutRect ) -{ - const bool bIsPrintTitle = rPrintUIOptions.getBoolValue( PRTUIOPT_TITLE_ROW, true ); - const bool bIsPrintFrame = rPrintUIOptions.getBoolValue( PRTUIOPT_BORDER, true ); - const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue( PRTUIOPT_FORMULA_TEXT, true ); - SmPrintSize ePrintSize( static_cast< SmPrintSize >( rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL ) )); - const sal_uInt16 nZoomFactor = static_cast< sal_uInt16 >(rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_SCALE, 100 )); - - rOutDev.Push(); - rOutDev.SetLineColor( COL_BLACK ); - - // output text on top - if (bIsPrintTitle) - { - Size aSize600 (0, 600); - Size aSize650 (0, 650); - vcl::Font aFont(FAMILY_DONTKNOW, aSize600); - - aFont.SetAlignment(ALIGN_TOP); - aFont.SetWeight(WEIGHT_BOLD); - aFont.SetFontSize(aSize650); - aFont.SetColor( COL_BLACK ); - rOutDev.SetFont(aFont); - - Size aTitleSize (GetTextSize(rOutDev, GetDoc()->GetTitle(), aOutRect.GetWidth() - 200)); - - aFont.SetWeight(WEIGHT_NORMAL); - aFont.SetFontSize(aSize600); - rOutDev.SetFont(aFont); - - Size aDescSize (GetTextSize(rOutDev, GetDoc()->GetComment(), aOutRect.GetWidth() - 200)); - - if (bIsPrintFrame) - rOutDev.DrawRect(tools::Rectangle(aOutRect.TopLeft(), - Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200 + aDescSize.Height() + 100))); - aOutRect.AdjustTop(200 ); - - // output title - aFont.SetWeight(WEIGHT_BOLD); - aFont.SetFontSize(aSize650); - rOutDev.SetFont(aFont); - Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2, - aOutRect.Top()); - DrawText(rOutDev, aPoint, GetDoc()->GetTitle(), - sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200)); - aOutRect.AdjustTop(aTitleSize.Height() + 200 ); - - // output description - aFont.SetWeight(WEIGHT_NORMAL); - aFont.SetFontSize(aSize600); - rOutDev.SetFont(aFont); - aPoint.setX( aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2 ); - aPoint.setY( aOutRect.Top() ); - DrawText(rOutDev, aPoint, GetDoc()->GetComment(), - sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200)); - aOutRect.AdjustTop(aDescSize.Height() + 300 ); - } - - // output text on bottom - if (bIsPrintFormulaText) - { - vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600)); - aFont.SetAlignment(ALIGN_TOP); - aFont.SetColor( COL_BLACK ); - - // get size - rOutDev.SetFont(aFont); - - Size aSize (GetTextSize(rOutDev, GetDoc()->GetText(), aOutRect.GetWidth() - 200)); - - aOutRect.AdjustBottom( -(aSize.Height() + 600) ); - - if (bIsPrintFrame) - rOutDev.DrawRect(tools::Rectangle(aOutRect.BottomLeft(), - Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200))); - - Point aPoint (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2, - aOutRect.Bottom() + 300); - DrawText(rOutDev, aPoint, GetDoc()->GetText(), - sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200)); - aOutRect.AdjustBottom( -200 ); - } - - if (bIsPrintFrame) - rOutDev.DrawRect(aOutRect); - - aOutRect.AdjustTop(100 ); - aOutRect.AdjustLeft(100 ); - aOutRect.AdjustBottom( -100 ); - aOutRect.AdjustRight( -100 ); - - Size aSize (GetDoc()->GetSize()); - - MapMode OutputMapMode; - // PDF export should always use PRINT_SIZE_NORMAL ... - if (!rPrintUIOptions.getBoolValue( "IsPrinter" ) ) - ePrintSize = PRINT_SIZE_NORMAL; - switch (ePrintSize) - { - case PRINT_SIZE_NORMAL: - OutputMapMode = MapMode(SmMapUnit()); - break; - - case PRINT_SIZE_SCALED: - if (!aSize.IsEmpty()) - { - Size OutputSize(rOutDev.LogicToPixel(aOutRect.GetSize(), MapMode(SmMapUnit()))); - Size GraphicSize(rOutDev.LogicToPixel(aSize, MapMode(SmMapUnit()))); - sal_uInt16 nZ = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()), - o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height())); - nZ -= 10; - Fraction aFraction(std::clamp(nZ, MINZOOM, sal_uInt16(100)), 1); - - OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); - } - else - OutputMapMode = MapMode(SmMapUnit()); - break; - - case PRINT_SIZE_ZOOMED: - { - Fraction aFraction( nZoomFactor, 100 ); - - OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction); - break; - } - } - - aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode), - MapMode(SmMapUnit())); - - Point aPos (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2, - aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2); - - aPos = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(SmMapUnit())), - OutputMapMode); - aOutRect = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(SmMapUnit())), - OutputMapMode); - - rOutDev.SetMapMode(OutputMapMode); - rOutDev.SetClipRegion(vcl::Region(aOutRect)); - GetDoc()->DrawFormula(rOutDev, aPos); - rOutDev.SetClipRegion(); - - rOutDev.Pop(); -} - SfxPrinter* SmViewShell::GetPrinter(bool bCreate) { SmDocShell* pDoc = GetDoc(); commit f64479dd729d83d3fa84fa1e97540f4ae0b37a2b Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Oct 28 18:06:34 2023 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Mon Oct 30 21:22:25 2023 +0300 pPrinter may be nullptr E.g., calling storeToURL, generating a PDF, on an embedded formula. Change-Id: If74af90f9c3dfd54a328782ddecd0adf52b51a5a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158591 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/starmath/source/unomodel.cxx b/starmath/source/unomodel.cxx index b7a92567fe25..89796c27e04f 100644 --- a/starmath/source/unomodel.cxx +++ b/starmath/source/unomodel.cxx @@ -910,8 +910,9 @@ uno::Sequence< beans::PropertyValue > SAL_CALL SmModel::getRenderer( throw RuntimeException(); SmPrinterAccess aPrinterAccess( *pDocSh ); - Printer *pPrinter = aPrinterAccess.GetPrinter(); - Size aPrtPaperSize ( pPrinter->GetPaperSize() ); + Size aPrtPaperSize; + if (Printer *pPrinter = aPrinterAccess.GetPrinter()) + aPrtPaperSize = pPrinter->GetPaperSize(); // if paper size is 0 (usually if no 'real' printer is found), // guess the paper size @@ -981,11 +982,16 @@ void SAL_CALL SmModel::render( return; SmPrinterAccess aPrinterAccess( *pDocSh ); - Printer *pPrinter = aPrinterAccess.GetPrinter(); - Size aPrtPaperSize ( pPrinter->GetPaperSize() ); - Size aOutputSize ( pPrinter->GetOutputSize() ); - Point aPrtPageOffset( pPrinter->GetPageOffset() ); + Size aPrtPaperSize; + Size aOutputSize; + Point aPrtPageOffset; + if (Printer *pPrinter = aPrinterAccess.GetPrinter()) + { + aPrtPaperSize = pPrinter->GetPaperSize(); + aOutputSize = pPrinter->GetOutputSize(); + aPrtPageOffset = pPrinter->GetPageOffset(); + } // no real printer ?? if (aPrtPaperSize.IsEmpty())