From 4ce8120f1e53f7b81e653b01d141643013bc69ab Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Fri, 24 Jan 2020 19:05:40 +0100 Subject: tdf#45589 sw: create and paint text portions for bookmarks Add a new SwBookmarkPortion, derived from SwControlCharPortion. There is no character for the bookmark in the text so the portion has length of 0, which makes things quite a bit more tricky. Formatting: * SwBookmarkPortion is created last in WhichFirstPortion(). * In an empty paragraph the SwTextFrame::FormatEmpty() must be disabled. * If there's a bookmark at the end of a paragraph, SwTextFormatter::CalcAscent() must use the font of the previous character, not the paragraph font, because that could grow the line if it's higher. * The SwMultiPortion complicates matters, because it uses a nested SwTextFormatInfo and thus we need some extra steps to prevent duplicate SwBookmarkPortions; this is particluarly a problem for rotated text portions. - SwTextFormatter::BuildPortions() must advance the outer SwTextFormatInfo's bookmark position because BuildMultiPortion() has already created the SwBookmarkPortion. - If a SwBookmarkPortion is at the start of a SwMultiPortion, it will be created before the SwMultiPortion but must be painted inside the SwMultiPortion because its font is going to be initialised as inside the SwMultiPortion (e.g. it will be rotated) so its position must also be adapted to be inside, and only SwTextPainter::PaintMultiPortion() does the setup for that; add a hack to move it in SwTextFormatter::BuildMultiPortion(). Painting: * Using the original font seems rather difficult, hard to predict what some character is going to look like, and how it scales if the size is increased; use OpenSymbol instead. Unfortunately OpenSymbol doesn't have a good glyph that could be used for both the end of a bookmark and start of another bookmark at the same position. * SwLinePortion::PrePaint() wants to avoid moving the portion half-outside the frame but often it looks better that way (previously it was misaligned, now it's half-outside). * Not sure if it makes sense to draw a field shading in SwTextPaintInfo::DrawViewOpt() too; let's try it out, but dependent on the same IsViewMetaChars() setting as the bookmark character itself, not on the field shading setting. Change-Id: I1ab94afb417221e278dbb3afd6c978a05fc78497 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87364 Reviewed-by: Michael Stahl Tested-by: Michael Stahl --- sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 10 ++- sw/source/core/access/accportions.cxx | 3 + sw/source/core/inc/scriptinfo.hxx | 11 ++- sw/source/core/inc/txttypes.hxx | 1 + sw/source/core/text/inftxt.cxx | 23 ++++++ sw/source/core/text/inftxt.hxx | 3 + sw/source/core/text/itrform2.cxx | 51 +++++++++++++ sw/source/core/text/porlay.cxx | 17 +++++ sw/source/core/text/porlin.cxx | 4 +- sw/source/core/text/porlin.hxx | 2 +- sw/source/core/text/pormulti.cxx | 14 ++++ sw/source/core/text/porrst.cxx | 122 +++++++++++++++++++++++++------ sw/source/core/text/porrst.hxx | 26 +++++++ sw/source/core/text/xmldump.cxx | 1 + 14 files changed, 262 insertions(+), 26 deletions(-) diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index a9edd2b66eb1..fb6fbde35536 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -318,8 +318,14 @@ DECLARE_OOXMLIMPORT_TEST(testN758883, "n758883.docx") * The problem was that direct formatting of the paragraph was not applied * to the numbering. This is easier to test using a layout dump. */ - OUString aHeight = parseDump("/root/page/body/txt/Special", "nHeight"); - CPPUNIT_ASSERT_EQUAL(sal_Int32(220), aHeight.toInt32()); // It was 280 + xmlDocPtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "/root/page/body/txt/Special[1]", "nHeight", "220"); + + // check the bookmark portions are of the expected height + assertXPath(pXmlDoc, "/root/page/body/txt/Special[2]", "nType", "PortionType::Bookmark"); + assertXPath(pXmlDoc, "/root/page/body/txt/Special[2]", "nHeight", "253"); + assertXPath(pXmlDoc, "/root/page/body/txt/Special[3]", "nType", "PortionType::Bookmark"); + assertXPath(pXmlDoc, "/root/page/body/txt/Special[3]", "nHeight", "253"); /* * Next problem was that the page margin contained the width of the page border as well. diff --git a/sw/source/core/access/accportions.cxx b/sw/source/core/access/accportions.cxx index 00cabbe14eba..b929bc54b5ac 100644 --- a/sw/source/core/access/accportions.cxx +++ b/sw/source/core/access/accportions.cxx @@ -170,6 +170,9 @@ void SwAccessiblePortionData::Special( case PortionType::ControlChar: sDisplay = rText + OUStringChar(m_pTextFrame->GetText()[sal_Int32(m_nViewPosition)]); break; + case PortionType::Bookmark: + // TODO + break; default: sDisplay = rText; break; diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index 6d7ad0f4dfff..bb91dedea1a7 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "TextFrameIndex.hxx" @@ -42,7 +43,7 @@ class SwScriptInfo { public: enum CompType { KANA, SPECIAL_LEFT, SPECIAL_RIGHT, NONE, SPECIAL_MIDDLE}; - enum class MarkKind { Start, End, Point }; + enum class MarkKind { Start = (1<<0), End = (1<<1), Point = (1<<2) }; private: //! Records a single change in script type. @@ -182,6 +183,7 @@ public: } TextFrameIndex NextHiddenChg(TextFrameIndex nPos) const; TextFrameIndex NextBookmark(TextFrameIndex nPos) const; + MarkKind GetBookmark(TextFrameIndex nPos) const; static void CalcHiddenRanges(const SwTextNode& rNode, MultiSelection& rHiddenMulti, std::vector> * pBookmarks); @@ -385,6 +387,13 @@ public: static SwFontScript WhichFont(sal_Int32 nIdx, OUString const & rText); }; +namespace o3tl +{ + +template<> struct typed_flags : is_typed_flags {}; + +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/txttypes.hxx b/sw/source/core/inc/txttypes.hxx index 2030fff25cc5..16f433e3b0b2 100644 --- a/sw/source/core/inc/txttypes.hxx +++ b/sw/source/core/inc/txttypes.hxx @@ -33,6 +33,7 @@ enum class PortionType Multi = 0x0085, HiddenText = 0x0086, ControlChar = 0x0087, + Bookmark = 0x0088, Text = 0x8000, Lay = 0x8001, diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index 83e8bde03ad3..8538d6ebabd4 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -1375,6 +1375,14 @@ void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor, bDraw = true; } break; + case PortionType::Bookmark: + if (!GetOpt().IsPagePreview() + && !GetOpt().IsReadonly() + && GetOpt().IsViewMetaChars()) + { + bDraw = true; + } + break; case PortionType::InputField: // input field shading also in read-only mode if ( !GetOpt().IsPagePreview() @@ -1582,6 +1590,7 @@ void SwTextFormatInfo::Init() m_nForcedLeftMargin = 0; m_nSoftHyphPos = TextFrameIndex(0); m_nUnderScorePos = TextFrameIndex(COMPLETE_STRING); + m_nLastBookmarkPos = TextFrameIndex(-1); m_cHookChar = 0; SetIdx(TextFrameIndex(0)); SetLen(TextFrameIndex(GetText().getLength())); @@ -2007,4 +2016,18 @@ bool SwTextFormatInfo::ChgHyph( const bool bNew ) return bOld; } + +bool SwTextFormatInfo::CheckCurrentPosBookmark() +{ + if (m_nLastBookmarkPos != GetIdx()) + { + m_nLastBookmarkPos = GetIdx(); + return true; + } + else + { + return false; + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx index 30888843626d..63d030e896e9 100644 --- a/sw/source/core/text/inftxt.hxx +++ b/sw/source/core/text/inftxt.hxx @@ -477,6 +477,7 @@ class SwTextFormatInfo : public SwTextPaintInfo TextFrameIndex m_nSoftHyphPos; ///< SoftHyphPos for Hyphenation TextFrameIndex m_nLineStart; ///< Current line start in rText TextFrameIndex m_nUnderScorePos; ///< enlarge repaint if underscore has been found + TextFrameIndex m_nLastBookmarkPos; ///< need to check for bookmarks at every portion // #i34348# Changed type from sal_uInt16 to SwTwips SwTwips m_nLeft; // Left margin SwTwips m_nRight; // Right margin @@ -636,6 +637,8 @@ public: bool IsArrowDone() const { return m_bArrowDone; } void SetArrowDone( const bool bNew ) { m_bArrowDone = bNew; } + bool CheckCurrentPosBookmark(); + // For SwTextPortion::Hyphenate bool ChgHyph( const bool bNew ); diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 3285f7f5ede9..6edf7e055184 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -691,6 +691,10 @@ void SwTextFormatter::BuildPortions( SwTextFormatInfo &rInf ) CalcAscent( rInf, pPor ); InsertPortion( rInf, pPor ); + if (pPor->IsMultiPortion() && (!m_pMulti || m_pMulti->IsBidi())) + { + (void) rInf.CheckCurrentPosBookmark(); // bookmark was already created inside MultiPortion! + } pPor = NewPortion( rInf ); } @@ -753,6 +757,19 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, SwLinePortion *pPor ) pPor->Height( pLast->Height() ); pPor->SetAscent( pLast->GetAscent() ); } + else if (pPor->GetWhichPor() == PortionType::Bookmark + && rInf.GetIdx() == TextFrameIndex(rInf.GetText().getLength())) + { + // bookmark at end of paragraph: *don't* advance iterator, use the + // current font instead; it's possible that there's a font size on the + // paragraph and it's overridden on the last line of the paragraph and + // we don't want to apply it via SwBookmarkPortion and grow the line + // height (example: n758883.docx) + SwLinePortion const*const pLast = rInf.GetLast(); + assert(pLast); + pPor->Height( pLast->Height() ); + pPor->SetAscent( pLast->GetAscent() ); + } else { const SwLinePortion *pLast = rInf.GetLast(); @@ -1012,6 +1029,7 @@ SwTextPortion *SwTextFormatter::NewTextPortion( SwTextFormatInfo &rInf ) return pPor; } +// first portions have no length SwLinePortion *SwTextFormatter::WhichFirstPortion(SwTextFormatInfo &rInf) { SwLinePortion *pPor = nullptr; @@ -1144,6 +1162,39 @@ SwLinePortion *SwTextFormatter::WhichFirstPortion(SwTextFormatInfo &rInf) pPor = TryNewNoLengthPortion(rInf); } + // 12. bookmarks + // check this *last* so that BuildMultiPortion() can find it! + if (!pPor && rInf.CheckCurrentPosBookmark()) + { + auto const bookmark(m_pScriptInfo->GetBookmark(rInf.GetIdx())); + if (static_cast(bookmark)) + { + sal_Unicode mark; + if ((bookmark & (SwScriptInfo::MarkKind::Start|SwScriptInfo::MarkKind::End)) + == (SwScriptInfo::MarkKind::Start|SwScriptInfo::MarkKind::End)) + { + //mark = u'\u2336'; // not in OpenSymbol :( + mark = '|'; + // hmm ... paint U+2345 over U+2346 should be same width? + // and U+237F // or U+2E20/U+2E21 + } + else if (bookmark & SwScriptInfo::MarkKind::Start) + { + mark = '['; + } + else if (bookmark & SwScriptInfo::MarkKind::End) + { + mark = ']'; + } + else + { + assert(bookmark & SwScriptInfo::MarkKind::Point); + mark = '|'; + } + pPor = new SwBookmarkPortion(rInf.GetLast(), mark); + } + } + return pPor; } diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index aa0bbf6860c3..9fa74a0d4833 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -1686,6 +1686,23 @@ TextFrameIndex SwScriptInfo::NextBookmark(TextFrameIndex const nPos) const return TextFrameIndex(COMPLETE_STRING); } +auto SwScriptInfo::GetBookmark(TextFrameIndex const nPos) const -> MarkKind +{ + MarkKind ret{0}; + for (auto const& it : m_Bookmarks) + { + if (nPos == it.first) + { + ret |= it.second; + } + else if (nPos < it.first) + { + break; + } + } + return ret; +} + // Takes a string and replaced the hidden ranges with cChar. sal_Int32 SwScriptInfo::MaskHiddenRanges( const SwTextNode& rNode, OUStringBuffer & rText, const sal_Int32 nStt, const sal_Int32 nEnd, diff --git a/sw/source/core/text/porlin.cxx b/sw/source/core/text/porlin.cxx index b5adccb07fba..3d5cb26aa4be 100644 --- a/sw/source/core/text/porlin.cxx +++ b/sw/source/core/text/porlin.cxx @@ -103,7 +103,9 @@ void SwLinePortion::PrePaint( const SwTextPaintInfo& rInf, 1800 : rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() ); - if (nLastWidth > nHalfView) + // pLast == this *only* for the 1st portion in the line so nLastWidth is 0; + // allow this too, will paint outside the frame but might look better... + if (nLastWidth > nHalfView || pLast == this) { switch (nDir) { diff --git a/sw/source/core/text/porlin.hxx b/sw/source/core/text/porlin.hxx index 3fe08cbacba4..ca7bc1a34fe1 100644 --- a/sw/source/core/text/porlin.hxx +++ b/sw/source/core/text/porlin.hxx @@ -133,7 +133,7 @@ public: bool IsArrowPortion() const { return nWhichPor == PortionType::Arrow; } bool IsMultiPortion() const { return nWhichPor == PortionType::Multi; } bool IsNumberPortion() const { return nWhichPor == PortionType::Number; } // #i23726# - bool IsControlCharPortion() const { return nWhichPor == PortionType::ControlChar; } + bool IsControlCharPortion() const { return nWhichPor == PortionType::ControlChar || nWhichPor == PortionType::Bookmark; } // Positioning SwLinePortion *FindPrevPortion( const SwLinePortion *pRoot ); diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx index 1ef0c04efd86..5e991cc4bed3 100644 --- a/sw/source/core/text/pormulti.cxx +++ b/sw/source/core/text/pormulti.cxx @@ -38,6 +38,7 @@ #include "itrform2.hxx" #include "porfld.hxx" #include "porglue.hxx" +#include "porrst.hxx" #include #include #include @@ -2029,6 +2030,19 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, aInf.SetNumDone( rInf.IsNumDone() ); aInf.SetFootnoteDone( rInf.IsFootnoteDone() ); + // if there's a bookmark at the start of the MultiPortion, it will be + // painted with the rotation etc. of the MultiPortion; move it *inside* + // so it gets positioned correctly; currently there's no other portion + // inserted between the end of WhichFirstPortion() and + // BuildMultiPortion() + if (rInf.GetLast()->GetWhichPor() == PortionType::Bookmark) + { + auto const pBookmark(static_cast(rInf.GetLast())); + rInf.SetLast(pBookmark->Unchain()); + assert(m_pCurr->GetNextPortion() == nullptr); + m_pCurr->SetNextPortion(pBookmark); + } + if( pFirstRest ) { OSL_ENSURE( pFirstRest->InFieldGrp(), "BuildMulti: Fieldrest expected"); diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx index 686959609cd8..44d2288eaf9c 100644 --- a/sw/source/core/text/porrst.cxx +++ b/sw/source/core/text/porrst.cxx @@ -306,6 +306,17 @@ bool SwTextFrame::FormatEmpty() aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) ) return false; + // only need to check one node because of early return on GetMerged() + for (SwIndex const* pIndex = GetTextNodeFirst()->GetFirstIndex(); + pIndex; pIndex = pIndex->GetNext()) + { + sw::mark::IMark const*const pMark = pIndex->GetMark(); + if (dynamic_cast(pMark) != nullptr) + { // need bookmark portions! + return false; + } + } + SwTwips nHeight = EmptyHeight(); if (aSet.GetParaGrid().GetValue() && @@ -488,35 +499,92 @@ bool SwHiddenTextPortion::Format( SwTextFormatInfo &rInf ) return false; }; +bool SwControlCharPortion::DoPaint(SwTextPaintInfo const&, + OUString & rOutString, SwFont & rTmpFont, int &) const +{ + if (mcChar == CHAR_ZWNBSP || !SwViewOption::IsFieldShadings()) + { + return false; + } + + switch (mcChar) + { + case CHAR_ZWSP: + rOutString = "/"; break; +// case CHAR_LRM : +// rText = sal_Unicode(0x2514); break; +// case CHAR_RLM : +// rText = sal_Unicode(0x2518); break; + default: + assert(false); + break; + } + + rTmpFont.SetEscapement( CHAR_ZWSP == mcChar ? DFLT_ESC_AUTO_SUB : -25 ); + const sal_uInt16 nProp = 40; + rTmpFont.SetProportion( nProp ); // a smaller font + + return true; +} + +bool SwBookmarkPortion::DoPaint(SwTextPaintInfo const& rInf, + OUString & rOutString, SwFont & rTmpFont, int & rDeltaY) const +{ + if (!rInf.GetOpt().IsViewMetaChars()) + { + return false; + } + + rOutString = OUStringChar(mcChar); + + // init font: we want OpenSymbol to ensure it doesn't look too crazy; + // thin and a bit higher than the surrounding text + auto const nOrigAscent(rTmpFont.GetAscent(rInf.GetVsh(), *rInf.GetOut())); + rTmpFont.SetName("OpenSymbol", rTmpFont.GetActual()); + Size size(rTmpFont.GetSize(rTmpFont.GetActual())); + // use also the external leading (line gap) of the portion, but don't use + // 100% of it because i can't figure out how to baseline align that + auto const nFactor = (Height() * 95) / size.Height(); + rTmpFont.SetProportion(nFactor); + rTmpFont.SetWeight(WEIGHT_THIN, rTmpFont.GetActual()); + rTmpFont.SetColor(NON_PRINTING_CHARACTER_COLOR); + // reset these to default... + rTmpFont.SetAlign(ALIGN_BASELINE); + rTmpFont.SetUnderline(LINESTYLE_NONE); + rTmpFont.SetOverline(LINESTYLE_NONE); + rTmpFont.SetStrikeout(STRIKEOUT_NONE); + rTmpFont.SetOutline(false); + rTmpFont.SetShadow(false); + rTmpFont.SetTransparent(false); + rTmpFont.SetEmphasisMark(FontEmphasisMark::NONE); + rTmpFont.SetEscapement(0); + rTmpFont.SetPitch(PITCH_DONTKNOW, rTmpFont.GetActual()); + rTmpFont.SetRelief(FontRelief::NONE); + + // adjust Y position to account for different baselines of the fonts + auto const nOSAscent(rTmpFont.GetAscent(rInf.GetVsh(), *rInf.GetOut())); + rDeltaY = nOSAscent - nOrigAscent; + + return true; +} + void SwControlCharPortion::Paint( const SwTextPaintInfo &rInf ) const { if ( Width() ) // is only set during prepaint mode { - rInf.DrawViewOpt( *this, PortionType::ControlChar ); + rInf.DrawViewOpt(*this, GetWhichPor()); - if ( !rInf.GetOpt().IsPagePreview() && - !rInf.GetOpt().IsReadonly() && - SwViewOption::IsFieldShadings() && - CHAR_ZWNBSP != mcChar ) + int deltaY(0); + SwFont aTmpFont( *rInf.GetFont() ); + OUString aOutString; + + if (rInf.OnWin() + && !rInf.GetOpt().IsPagePreview() + && !rInf.GetOpt().IsReadonly() + && DoPaint(rInf, aOutString, aTmpFont, deltaY)) { - SwFont aTmpFont( *rInf.GetFont() ); - aTmpFont.SetEscapement( CHAR_ZWSP == mcChar ? DFLT_ESC_AUTO_SUB : -25 ); - const sal_uInt16 nProp = 40; - aTmpFont.SetProportion( nProp ); // a smaller font SwFontSave aFontSave( rInf, &aTmpFont ); - OUString aOutString; - - switch ( mcChar ) - { - case CHAR_ZWSP : - aOutString = "/"; break; -// case CHAR_LRM : -// rText = sal_Unicode(0x2514); break; -// case CHAR_RLM : -// rText = sal_Unicode(0x2518); break; - } - if ( !mnHalfCharWidth ) mnHalfCharWidth = rInf.GetTextSize( aOutString ).Width() / 2; @@ -527,12 +595,15 @@ void SwControlCharPortion::Paint( const SwTextPaintInfo &rInf ) const { case 0: aNewPos.AdjustX(deltaX); + aNewPos.AdjustY(deltaY); break; case 900: aNewPos.AdjustY(-deltaX); + aNewPos.AdjustX(deltaY); break; case 2700: aNewPos.AdjustY(deltaX); + aNewPos.AdjustX(-deltaY); break; default: assert(false); @@ -565,4 +636,13 @@ sal_uInt16 SwControlCharPortion::GetViewWidth( const SwTextSizeInfo& rInf ) cons return mnViewWidth; } +SwLinePortion * SwBookmarkPortion::Unchain() +{ + assert(!m_pPrevious || m_pPrevious->GetNextPortion() == this); + m_pPrevious->SetNextPortion(nullptr); + auto const pTmp(m_pPrevious); + m_pPrevious = nullptr; + return pTmp; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/porrst.hxx b/sw/source/core/text/porrst.hxx index 85e85d1570dd..dcb2cfcae7e9 100644 --- a/sw/source/core/text/porrst.hxx +++ b/sw/source/core/text/porrst.hxx @@ -31,6 +31,7 @@ class SwPortionHandler; class SwTextPaintInfo; class SwTextSizeInfo; +class SwFont; #define LINE_BREAK_WIDTH 150 #define SPECIAL_FONT_HEIGHT 200 @@ -133,6 +134,7 @@ class SwControlCharPortion : public SwLinePortion private: mutable sal_uInt16 mnViewWidth; // used to cache a calculated value mutable sal_uInt16 mnHalfCharWidth; // used to cache a calculated value +protected: sal_Unicode const mcChar; public: @@ -143,11 +145,35 @@ public: SetWhichPor( PortionType::ControlChar ); SetLen( TextFrameIndex(1) ); } + virtual bool DoPaint(SwTextPaintInfo const& rInf, + OUString & rOutString, SwFont & rTmpFont, int & rDeltaY) const; virtual void Paint( const SwTextPaintInfo &rInf ) const override; virtual bool Format( SwTextFormatInfo &rInf ) override; virtual sal_uInt16 GetViewWidth( const SwTextSizeInfo& rInf ) const override; }; +/// for showing bookmark starts and ends; note that in contrast to +/// SwControlCharPortion these do not have a character in the text. +class SwBookmarkPortion : public SwControlCharPortion +{ +private: + SwLinePortion * m_pPrevious; + +public: + explicit SwBookmarkPortion(SwLinePortion *const pPrevious, sal_Unicode const cChar) + : SwControlCharPortion(cChar) + , m_pPrevious(pPrevious) + { + SetWhichPor(PortionType::Bookmark); + SetLen(TextFrameIndex(0)); + } + + virtual bool DoPaint(SwTextPaintInfo const& rInf, + OUString & rOutString, SwFont & rTmpFont, int & rDeltaY) const override; + virtual SwLinePortion * Compress() override { return this; } + SwLinePortion * Unchain(); +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/xmldump.cxx b/sw/source/core/text/xmldump.cxx index 510615b08a1f..3db640cb4774 100644 --- a/sw/source/core/text/xmldump.cxx +++ b/sw/source/core/text/xmldump.cxx @@ -52,6 +52,7 @@ class XmlPortionDumper:public SwPortionHandler case PortionType::Multi: return "PortionType::Multi"; case PortionType::HiddenText: return "PortionType::HiddenText"; case PortionType::ControlChar: return "PortionType::ControlChar"; + case PortionType::Bookmark: return "PortionType::Bookmark"; case PortionType::Text: return "PortionType::Text"; case PortionType::Lay: return "PortionType::Lay"; -- cgit