oox/inc/oox/vml/vmlshape.hxx | 2 oox/inc/oox/vml/vmltextbox.hxx | 11 ++- oox/inc/oox/vml/vmltextboxcontext.hxx | 1 oox/source/vml/vmlshape.cxx | 15 +++- oox/source/vml/vmlshapecontext.cxx | 11 ++- oox/source/vml/vmltextbox.cxx | 36 +++++++++- oox/source/vml/vmltextboxcontext.cxx | 45 +++++++++++++ sw/qa/extras/ooxmlimport/data/n792778.docx |binary sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 62 ++++++++++++++---- writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 42 +++++++----- 10 files changed, 183 insertions(+), 42 deletions(-)
New commits: commit ffe1f48310f9a1dd4b64315bb16c312482b3f287 Author: Miklos Vajna <vmik...@suse.cz> Date: Sat Dec 15 17:28:14 2012 +0100 n#792778 testcase Change-Id: I0f86c70f5068b32e2a1cf1ac605e32b7e5903e94 diff --git a/sw/qa/extras/ooxmlimport/data/n792778.docx b/sw/qa/extras/ooxmlimport/data/n792778.docx new file mode 100755 index 0000000..d9541d4 Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/n792778.docx differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 11fcd11..5778f37 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -110,6 +110,7 @@ public: void testN773061(); void testN780645(); void testFineTableDash(); + void testN792778(); CPPUNIT_TEST_SUITE(Test); #if !defined(MACOSX) && !defined(WNT) @@ -171,7 +172,8 @@ void Test::run() {"n785767.docx", &Test::testN785767}, {"n773061.docx", &Test::testN773061}, {"n780645.docx", &Test::testN780645}, - {"tableborder-finedash.docx", &Test::testFineTableDash} + {"tableborder-finedash.docx", &Test::testFineTableDash}, + {"n792778.docx", &Test::testN792778}, }; for (unsigned int i = 0; i < SAL_N_ELEMENTS(aMethods); ++i) { @@ -1061,6 +1063,37 @@ void Test::testFineTableDash() CPPUNIT_ASSERT_EQUAL(aBorder.RightLine.LineStyle, table::BorderLineStyle::FINE_DASHED); } +void Test::testN792778() +{ + /* + * The problem was that the importer didn't handle complex groupshapes with groupshapes, textboxes and graphics inside. + * + * xray ThisComponent.DrawPage.Count ' 1 groupshape + * xray ThisComponent.DrawPage(0).Count ' 2 sub-groupshapes + * xray ThisComponent.DrawPage(0).getByIndex(0).Count ' first sub-groupshape: 1 pic + * xray ThisComponent.DrawPage(0).getByIndex(1).Count ' second sub-groupshape: 1 pic + * xray ThisComponent.DrawPage(0).getByIndex(0).getByIndex(0).Position.Y ' 11684, the vertical position of the shapes were also wrong + * xray ThisComponent.DrawPage(0).getByIndex(1).getByIndex(0).Position.Y ' 11684 + */ + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<container::XIndexAccess> xDrawPage(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount()); + + uno::Reference<drawing::XShapes> xGroupShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xGroupShape->getCount()); + + uno::Reference<drawing::XShapes> xInnerGroupShape(xGroupShape->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xInnerGroupShape->getCount()); + + uno::Reference<drawing::XShape> xInnerShape(xInnerGroupShape->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(11684), xInnerShape->getPosition().Y); + + xInnerGroupShape.set(xGroupShape->getByIndex(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xInnerGroupShape->getCount()); + + xInnerShape.set(xInnerGroupShape->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(11684), xInnerShape->getPosition().Y); +} CPPUNIT_TEST_SUITE_REGISTRATION(Test); CPPUNIT_PLUGIN_IMPLEMENT(); commit d5c934d150cb6cea5f96cbbee4fb5e8312bf027e Author: Miklos Vajna <vmik...@suse.cz> Date: Fri Dec 14 18:16:56 2012 +0100 n#792778 DOCX import: parse group shapes in oox only Previously textframes inside groupshapes were tried to be imported as TextFrames, but then their addition to a GroupShape failed, so the text simply ended up as a normal paragraph. Fix this by importing members of groupshapes as drawinglayer objects, just like how the WW8 import does. Also fix two testcases, which implicitely tested that the groupshape VML element is ignored on import. Change-Id: I1a9fba8a5fd532203a825e55b1d5996277ea12fa diff --git a/oox/inc/oox/vml/vmlshape.hxx b/oox/inc/oox/vml/vmlshape.hxx index 87b51d1..35d3a85 100644 --- a/oox/inc/oox/vml/vmlshape.hxx +++ b/oox/inc/oox/vml/vmlshape.hxx @@ -202,7 +202,7 @@ struct ShapeModel ~ShapeModel(); /** Creates and returns a new shape textbox structure. */ - TextBox& createTextBox(); + TextBox& createTextBox(ShapeTypeModel& rModel); /** Creates and returns a new shape client data structure. */ ClientData& createClientData(); }; diff --git a/oox/inc/oox/vml/vmltextbox.hxx b/oox/inc/oox/vml/vmltextbox.hxx index af69e77..4981443 100644 --- a/oox/inc/oox/vml/vmltextbox.hxx +++ b/oox/inc/oox/vml/vmltextbox.hxx @@ -24,10 +24,17 @@ #include <rtl/ustring.hxx> #include "oox/helper/helper.hxx" #include "oox/dllapi.h" +#include <com/sun/star/uno/Reference.h> + +namespace com { namespace sun { namespace star { + namespace drawing { class XShape; } +} } } namespace oox { namespace vml { +class ShapeTypeModel; + // ============================================================================ /** Font settings for a text portion in a textbox. */ @@ -62,7 +69,7 @@ struct TextPortionModel class OOX_DLLPUBLIC TextBox { public: - explicit TextBox(); + explicit TextBox(ShapeTypeModel& rTypeModel); /** Appends a new text portion to the textbox. */ void appendPortion( const TextFontModel& rFont, const ::rtl::OUString& rText ); @@ -73,7 +80,9 @@ public: const TextFontModel* getFirstFont() const; /** Returns the entire text of all text portions. */ ::rtl::OUString getText() const; + void convert(com::sun::star::uno::Reference<com::sun::star::drawing::XShape> xShape) const; + ShapeTypeModel& mrTypeModel; /// Text distance from the border (inset attribute of v:textbox), valid only if set. bool borderDistanceSet; int borderDistanceLeft, borderDistanceTop, borderDistanceRight, borderDistanceBottom; diff --git a/oox/inc/oox/vml/vmltextboxcontext.hxx b/oox/inc/oox/vml/vmltextboxcontext.hxx index 4fd35d1..a644026 100644 --- a/oox/inc/oox/vml/vmltextboxcontext.hxx +++ b/oox/inc/oox/vml/vmltextboxcontext.hxx @@ -41,6 +41,7 @@ public: virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ); virtual void onCharacters( const ::rtl::OUString& rChars ); + virtual void onStartElement(const AttributeList& rAttribs); virtual void onEndElement(); private: diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index df6d3b5..6b280b4 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -233,9 +233,9 @@ ShapeModel::~ShapeModel() { } -TextBox& ShapeModel::createTextBox() +TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel) { - mxTextBox.reset( new TextBox ); + mxTextBox.reset( new TextBox(rModel) ); return *mxTextBox; } @@ -486,6 +486,9 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) ); } } + + if (getTextBox()) + getTextBox()->convert(xShape); } // Import Legacy Fragments (if any) @@ -522,8 +525,9 @@ Reference< XShape > SimpleShape::createPictureObject( const Reference< XShapes > { aPropSet.setProperty( PROP_GraphicURL, aGraphicUrl ); } - // If the shape has an absolute position, set the properties accordingly. - if ( maTypeModel.maPosition == "absolute" ) + uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY); + // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape. + if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape")) { aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X); aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y); @@ -866,6 +870,9 @@ Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes > catch( Exception& ) { } + // Make sure group shapes are inline as well, unless there is an explicit different style. + PropertySet aPropertySet(xGroupShape); + lcl_SetAnchorType(aPropertySet, maTypeModel); return xGroupShape; } diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index 165b735..cb3daa6 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -404,10 +404,13 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 nElement, const Attri if( isRootElement() ) switch( nElement ) { case VML_TOKEN( textbox ): - // Custom shape in Writer with a textbox are transformed into a frame - dynamic_cast<SimpleShape&>( mrShape ).setService( - "com.sun.star.text.TextFrame"); - return new TextBoxContext( *this, mrShapeModel.createTextBox(), rAttribs, + if (getParentElement() != VML_TOKEN( group )) + { + // Custom shape in Writer with a textbox are transformed into a frame + dynamic_cast<SimpleShape&>( mrShape ).setService( + "com.sun.star.text.TextFrame"); + } + return new TextBoxContext( *this, mrShapeModel.createTextBox(mrShape.getTypeModel()), rAttribs, mrShape.getDrawing().getFilter().getGraphicHelper()); case VMLX_TOKEN( ClientData ): return new ClientDataContext( *this, mrShapeModel.createClientData(), rAttribs ); diff --git a/oox/source/vml/vmltextbox.cxx b/oox/source/vml/vmltextbox.cxx index 03c4eff..4af0a9d 100644 --- a/oox/source/vml/vmltextbox.cxx +++ b/oox/source/vml/vmltextbox.cxx @@ -20,12 +20,15 @@ #include "oox/vml/vmltextbox.hxx" #include <rtl/ustrbuf.hxx> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/text/XTextAppend.hpp> namespace oox { namespace vml { using ::rtl::OUString; using ::rtl::OUStringBuffer; +using namespace com::sun::star; TextFontModel::TextFontModel() { @@ -37,8 +40,9 @@ TextPortionModel::TextPortionModel( const TextFontModel& rFont, const OUString& { } -TextBox::TextBox() - : borderDistanceSet( false ) +TextBox::TextBox(ShapeTypeModel& rTypeModel) + : mrTypeModel(rTypeModel), + borderDistanceSet( false ) { } @@ -60,6 +64,34 @@ OUString TextBox::getText() const return aBuffer.makeStringAndClear(); } +void TextBox::convert(uno::Reference<drawing::XShape> xShape) const +{ + uno::Reference<text::XTextAppend> xTextAppend(xShape, uno::UNO_QUERY); + for (PortionVector::const_iterator aIt = maPortions.begin(), aEnd = maPortions.end(); aIt != aEnd; ++aIt) + { + beans::PropertyValue aPropertyValue; + std::vector<beans::PropertyValue> aPropVec; + const TextFontModel& rFont = aIt->maFont; + if (rFont.mobBold.has()) + { + aPropertyValue.Name = "CharWeight"; + aPropertyValue.Value = uno::makeAny(rFont.mobBold.get() ? awt::FontWeight::BOLD : awt::FontWeight::NORMAL); + aPropVec.push_back(aPropertyValue); + } + if (rFont.monSize.has()) + { + aPropertyValue.Name = "CharHeight"; + aPropertyValue.Value = uno::makeAny(double(rFont.monSize.get()) / 2.); + aPropVec.push_back(aPropertyValue); + } + uno::Sequence<beans::PropertyValue> aPropSeq(aPropVec.size()); + beans::PropertyValue* pValues = aPropSeq.getArray(); + for (std::vector<beans::PropertyValue>::iterator i = aPropVec.begin(); i != aPropVec.end(); ++i) + *pValues++ = *i; + xTextAppend->appendTextPortion(aIt->maText, aPropSeq); + } +} + } // namespace vml } // namespace oox diff --git a/oox/source/vml/vmltextboxcontext.cxx b/oox/source/vml/vmltextboxcontext.cxx index 2724a1f..3755cc7 100644 --- a/oox/source/vml/vmltextboxcontext.cxx +++ b/oox/source/vml/vmltextboxcontext.cxx @@ -19,6 +19,8 @@ #include "oox/vml/vmlformatting.hxx" #include "oox/vml/vmltextboxcontext.hxx" +#include "oox/vml/vmlshape.hxx" +#include <com/sun/star/drawing/XShape.hpp> namespace oox { namespace vml { @@ -68,7 +70,22 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent, OSL_ENSURE( !maFont.mobStrikeout, "TextPortionContext::TextPortionContext - nested <s> elements" ); maFont.mobStrikeout = true; break; + case OOX_TOKEN(dml, blip): + { + OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(embed)); + if (oRelId.has()) + mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get()); + } + break; + case VML_TOKEN(imagedata): + { + OptValue<OUString> oRelId = rAttribs.getString(R_TOKEN(id)); + if (oRelId.has()) + mrTextBox.mrTypeModel.moGraphicPath = getFragmentPathFromRelId(oRelId.get()); + } + break; case XML_span: + case OOX_TOKEN(doc, r): break; default: OSL_ENSURE( false, "TextPortionContext::TextPortionContext - unknown element" ); @@ -78,11 +95,16 @@ TextPortionContext::TextPortionContext( ContextHandler2Helper& rParent, ContextHandlerRef TextPortionContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) { OSL_ENSURE( nElement != XML_font, "TextPortionContext::onCreateContext - nested <font> elements" ); + if (getNamespace(getCurrentElement()) == NMSP_doc) + return this; return new TextPortionContext( *this, mrTextBox, maFont, nElement, rAttribs ); } void TextPortionContext::onCharacters( const OUString& rChars ) { + if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != OOX_TOKEN(doc, t)) + return; + switch( getCurrentElement() ) { case XML_span: @@ -94,8 +116,24 @@ void TextPortionContext::onCharacters( const OUString& rChars ) } } +void TextPortionContext::onStartElement(const AttributeList& rAttribs) +{ + switch (getCurrentElement()) + { + case OOX_TOKEN(doc, b): + maFont.mobBold = true; + break; + case OOX_TOKEN(doc, sz): + maFont.monSize = rAttribs.getInteger( OOX_TOKEN(doc, val) ); + break; + } +} + void TextPortionContext::onEndElement() { + if (getNamespace(getCurrentElement()) == NMSP_doc && getCurrentElement() != OOX_TOKEN(doc, t)) + return; + /* A child element without own child elements may contain a single space character, for example: @@ -149,10 +187,17 @@ ContextHandlerRef TextBoxContext::onCreateContext( sal_Int32 nElement, const Att { case VML_TOKEN( textbox ): if( nElement == XML_div ) return this; + else if (nElement == OOX_TOKEN(doc, txbxContent)) return this; break; case XML_div: if( nElement == XML_font ) return new TextPortionContext( *this, mrTextBox, TextFontModel(), nElement, rAttribs ); break; + case OOX_TOKEN(doc, txbxContent): + if (nElement == OOX_TOKEN(doc, p)) return this; + break; + case OOX_TOKEN(doc, p): + if (nElement == OOX_TOKEN(doc, r)) return new TextPortionContext( *this, mrTextBox, TextFontModel(), nElement, rAttribs ); + break; } return 0; } diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 7f78cfe..11fcd11 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -317,26 +317,28 @@ void Test::testFdo49940() void Test::testN751077() { /* -enum = ThisComponent.Text.createEnumeration -enum.NextElement -para = enum.NextElement -xray para.String -xray para.PageStyleName +xray ThisComponent.DrawPage(1).getByIndex(0).String +xray ThisComponent.DrawPage(1).getByIndex(0).Anchor.PageStyleName */ - uno::Reference<uno::XInterface> paragraph(getParagraph( 2, "TEXT1" )); - // we want to test the paragraph is on the first page (it was put onto another page without the fix), + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xTextDocument, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference<drawing::XShapes> xShapes(xDrawPage->getByIndex(1), uno::UNO_QUERY); + uno::Reference<text::XTextRange> xShape(xShapes->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("TEXT1"), xShape->getString()); + // we want to test the textbox is on the first page (it was put onto another page without the fix), // use a small trick and instead of checking the page layout, check the page style - OUString pageStyle = getProperty< OUString >( paragraph, "PageStyleName" ); - CPPUNIT_ASSERT_EQUAL( OUString( "First Page" ), pageStyle ); + uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("First Page"), getProperty<OUString>(xTextContent->getAnchor(), "PageStyleName")); } void Test::testN705956_1() { /* Get the first image in the document and check it's the one image in the document. -It should be also anchored inline (as character). +It should be also anchored inline (as character) and be inside a groupshape. image = ThisComponent.DrawPage.getByIndex(0) -graphic = image.Graphic +graphic = image(0).Graphic xray graphic.Size xray image.AnchorType */ @@ -344,8 +346,9 @@ xray image.AnchorType uno::Reference<drawing::XDrawPageSupplier> drawPageSupplier(textDocument, uno::UNO_QUERY); uno::Reference<drawing::XDrawPage> drawPage = drawPageSupplier->getDrawPage(); CPPUNIT_ASSERT_EQUAL( sal_Int32( 1 ), drawPage->getCount()); + uno::Reference<drawing::XShapes> shapes(drawPage->getByIndex(0), uno::UNO_QUERY); uno::Reference<drawing::XShape> image; - drawPage->getByIndex(0) >>= image; + shapes->getByIndex(0) >>= image; uno::Reference<beans::XPropertySet> imageProperties(image, uno::UNO_QUERY); uno::Reference<graphic::XGraphic> graphic; imageProperties->getPropertyValue( "Graphic" ) >>= graphic; diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index 37c3336..5865846 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -2073,6 +2073,7 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext { uno::Reference< xml::sax::XFastContextHandler > xContextHandler; + bool bGroupShape = Element == Token_t(NS_vml | OOXML_group); sal_uInt32 nNamespace = Element & 0xffff0000; switch (nNamespace) @@ -2080,26 +2081,33 @@ OOXMLFastContextHandlerShape::lcl_createFastChildContext case NS_wordprocessingml: case NS_vml_wordprocessingDrawing: case NS_office: - xContextHandler.set(OOXMLFactory::getInstance()->createFastChildContextFromStart(this, Element)); - break; + if (!bGroupShape) + xContextHandler.set(OOXMLFactory::getInstance()->createFastChildContextFromStart(this, Element)); + // no break; default: - if (mrShapeContext.is()) + if (!xContextHandler.is()) { - uno::Reference<XFastContextHandler> pChildContext = - mrShapeContext->createFastChildContext(Element, Attribs); - - OOXMLFastContextHandlerWrapper * pWrapper = - new OOXMLFastContextHandlerWrapper(this, pChildContext); - - pWrapper->addNamespace(NS_wordprocessingml); - pWrapper->addNamespace(NS_vml_wordprocessingDrawing); - pWrapper->addNamespace(NS_office); - pWrapper->addToken( NS_vml|OOXML_textbox ); - - xContextHandler.set(pWrapper); + if (mrShapeContext.is()) + { + uno::Reference<XFastContextHandler> pChildContext = + mrShapeContext->createFastChildContext(Element, Attribs); + + OOXMLFastContextHandlerWrapper * pWrapper = + new OOXMLFastContextHandlerWrapper(this, pChildContext); + + if (!bGroupShape) + { + pWrapper->addNamespace(NS_wordprocessingml); + pWrapper->addNamespace(NS_vml_wordprocessingDrawing); + pWrapper->addNamespace(NS_office); + pWrapper->addToken( NS_vml|OOXML_textbox ); + } + + xContextHandler.set(pWrapper); + } + else + xContextHandler.set(this); } - else - xContextHandler.set(this); break; } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits