389 lines
12 KiB
C++
389 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <editeng/txtrange.hxx>
|
|
#include <swtypes.hxx>
|
|
#include <swrect.hxx>
|
|
#include <com/sun/star/text/WrapTextMode.hpp>
|
|
#include <nodeoffset.hxx>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
class OutputDevice;
|
|
class SwPageFrame;
|
|
class SdrObject;
|
|
class SwFormat;
|
|
class SwAnchoredObject;
|
|
class SwTextFrame;
|
|
class SwDrawTextInfo;
|
|
class SwContourCache;
|
|
class SwBreakPortion;
|
|
class SwTextFormatInfo;
|
|
|
|
typedef std::vector< SwAnchoredObject* > SwAnchoredObjList;
|
|
|
|
/** Contour-cache global variable, initialized/destroyed in txtinit.cxx
|
|
and needed in txtfly.cxx by text wrapping.
|
|
*/
|
|
extern SwContourCache *pContourCache;
|
|
|
|
#define POLY_CNT 20
|
|
#define POLY_MIN 5
|
|
#define POLY_MAX 4000
|
|
|
|
void ClrContourCache( const SdrObject *pObj );
|
|
|
|
class SwContourCache
|
|
{
|
|
friend void ClrContourCache();
|
|
struct CacheItem
|
|
{
|
|
const SdrObject *mpSdrObj;
|
|
std::unique_ptr<TextRanger> mxTextRanger;
|
|
};
|
|
std::vector<CacheItem> mvItems;
|
|
tools::Long mnPointCount;
|
|
SwRect ContourRect( const SwFormat* pFormat, const SdrObject* pObj,
|
|
const SwTextFrame* pFrame, const SwRect &rLine, const tools::Long nXPos,
|
|
const bool bRight );
|
|
|
|
public:
|
|
SwContourCache();
|
|
~SwContourCache();
|
|
const SdrObject* GetObject( sal_uInt16 nPos ) const{ return mvItems[ nPos ].mpSdrObj; }
|
|
sal_uInt16 GetCount() const { return mvItems.size(); }
|
|
void ClrObject( sal_uInt16 nPos );
|
|
|
|
/**
|
|
Computes the rectangle that will cover the object in the given line.
|
|
|
|
For _non_ contour-flow objects, this is simply the overlap area of
|
|
BoundRect (including spacing), and the line, for contour-flow,
|
|
the tools::PolyPolygon of the object gets traversed
|
|
*/
|
|
static SwRect CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
|
|
const SwRect &rLine,
|
|
const SwTextFrame* pFrame,
|
|
const tools::Long nXPos,
|
|
const bool bRight );
|
|
};
|
|
|
|
// MS Word wraps on sides with even less space (value guessed).
|
|
#define TEXT_MIN_SMALL 300
|
|
|
|
/**
|
|
The purpose of this class is to be the universal interface between
|
|
formatting/text output and the possibly overlapping free-flying frames.
|
|
During formatting the formatter gets the information from SwTextFly, whether
|
|
a certain area is present by the attributes of an overlapping frame.
|
|
Such areas are represented by dummy portions.
|
|
|
|
The whole text output and touch-up is, again, forwarded to a SwTextFly.
|
|
This one decides, whether parts of the text need to be clipped and splits
|
|
the areas for e.g. a DrawRect.
|
|
|
|
Please note that all free-flying frames are located in a PtrArray, sorted
|
|
by TopLeft.
|
|
|
|
Internally we always use document-global values. The IN and OUT parameters
|
|
are, however, adjusted to the needs of the LineIter most of the time. That
|
|
is: they are converted to frame- and window-local coordinates.
|
|
If multiple frames with wrap attributes are located on the same line, we get
|
|
the following settings for the text flow:
|
|
|
|
L/R P L R N
|
|
P -P-P- -P-L -P R- -P N
|
|
L -L P- -L L -L R- -L N
|
|
R R-P- R-L R R- R N
|
|
N N P- N L N R- N N
|
|
|
|
(P=parallel, L=left, R=right, N=no wrap)
|
|
|
|
We can describe the behaviour as follows:
|
|
Every frame can push away text, with the restriction that it only has influence
|
|
until the next frame.
|
|
*/
|
|
class SwTextFly
|
|
{
|
|
const SwPageFrame * m_pPage;
|
|
const SwAnchoredObject * mpCurrAnchoredObj;
|
|
const SwTextFrame * m_pCurrFrame;
|
|
const SwTextFrame * m_pMaster;
|
|
std::unique_ptr<SwAnchoredObjList> mpAnchoredObjList;
|
|
|
|
tools::Long m_nMinBottom;
|
|
tools::Long m_nNextTop; /// Stores the upper edge of the "next" frame
|
|
SwNodeOffset m_nCurrFrameNodeIndex;
|
|
|
|
bool m_bOn : 1;
|
|
bool m_bTopRule: 1;
|
|
bool mbIgnoreCurrentFrame: 1;
|
|
bool mbIgnoreContour: 1;
|
|
|
|
/** boolean, indicating if objects in page header|footer are considered for
|
|
text frames not in page header|footer.
|
|
*/
|
|
bool mbIgnoreObjsInHeaderFooter: 1;
|
|
|
|
/**
|
|
This method will be called during the LineIter formatting
|
|
\li to compute the position of the next \c FlyPortion
|
|
\li remember new overlappings after a change of the line height.
|
|
|
|
\param[in] rPortion
|
|
Scope: document global.
|
|
*/
|
|
SwRect GetFrame_( const SwRect &rPortion ) const;
|
|
|
|
SwAnchoredObjList& InitAnchoredObjList();
|
|
|
|
public:
|
|
SwAnchoredObjList& GetAnchoredObjList() const;
|
|
private:
|
|
|
|
/**
|
|
Look for the first object which overlaps with the rectangle.
|
|
Iterates over the anchored object list mpAnchoredObjList.
|
|
*/
|
|
bool ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const;
|
|
|
|
/**
|
|
\li There is less than 2cm space on both sides for the text:
|
|
no surround (css::text::WrapTextMode_NONE)
|
|
|
|
\li There is more than 2cm space on only one side:
|
|
surround on that side (css::text::WrapTextMode_LEFT or css::text::WrapTextMode_RIGHT)
|
|
|
|
\li There is more than 2cm space on both sides, the object is
|
|
larger than 1.5cm: surround on the wider side
|
|
(css::text::WrapTextMode_LEFT or css::text::WrapTextMode_RIGHT)
|
|
|
|
\li There is more than 2cm space on both sides and the object
|
|
width is less than 1.5cm: both sides surround (css::text::WrapTextMode_PARALLEL)
|
|
*/
|
|
css::text::WrapTextMode GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const;
|
|
|
|
/**
|
|
The right margin is the right margin or it is determined by the
|
|
next object standing on the line.
|
|
*/
|
|
void CalcRightMargin( SwRect &rFly,
|
|
SwAnchoredObjList::size_type nPos,
|
|
const SwRect &rLine ) const;
|
|
|
|
/**
|
|
The left margin is the left margin of the current PrintArea or
|
|
it is determined by the last FlyFrame, which stands on the line.
|
|
*/
|
|
void CalcLeftMargin( SwRect &rFly,
|
|
SwAnchoredObjList::size_type nPos,
|
|
const SwRect &rLine ) const;
|
|
|
|
/**
|
|
\return the position in sorted array
|
|
*/
|
|
SwAnchoredObjList::size_type GetPos( const SwAnchoredObject* pAnchoredObj ) const;
|
|
|
|
bool GetTop( const SwAnchoredObject* _pAnchoredObj,
|
|
const bool bInFootnote,
|
|
const bool bInFooterOrHeader );
|
|
|
|
SwTwips CalcMinBottom() const;
|
|
|
|
const SwTextFrame* GetMaster_();
|
|
|
|
public:
|
|
|
|
SwTextFly();
|
|
SwTextFly( const SwTextFrame *pFrame );
|
|
SwTextFly( const SwTextFly& rTextFly );
|
|
~SwTextFly();
|
|
|
|
void CtorInitTextFly( const SwTextFrame *pFrame );
|
|
|
|
void SetTopRule();
|
|
|
|
SwRect GetFrame( const SwRect &rPortion ) const;
|
|
bool IsOn() const;
|
|
|
|
/**
|
|
If there is no flying object frame standing in rRect (usually the current row),
|
|
then we are turning ourself off.
|
|
|
|
\param rRect is global to the document!
|
|
*/
|
|
bool Relax( const SwRect &rRect );
|
|
bool Relax();
|
|
|
|
SwTwips GetMinBottom() const;
|
|
|
|
/// Gets the maximum of the fly frame bottoms.
|
|
SwTwips GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const;
|
|
|
|
const SwTextFrame* GetMaster() const;
|
|
|
|
// This temporary variable needs to be manipulated in const methods
|
|
tools::Long GetNextTop() const;
|
|
void SetNextTop( tools::Long nNew ) const;
|
|
|
|
/**
|
|
Determines the demanded rectangle for an anchored object,
|
|
considering its surround for text wrapping.
|
|
|
|
\param pAnchoredObj the object for which to get the bounds
|
|
\param rLine the bounds of the line to format
|
|
|
|
\return the flying object bounds
|
|
*/
|
|
SwRect AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
|
|
const SwRect& rRect ) const;
|
|
|
|
/**
|
|
This method is called by DrawText().
|
|
|
|
Ensures that the overlapping frames (except the transparent frames) won't
|
|
be scribbled by setting clip regions so that only the portions that are not
|
|
in the area of FlyFrames that are opaque and above the current frame will
|
|
be output.
|
|
|
|
DrawText() takes over the on optimization!
|
|
*/
|
|
void DrawTextOpaque( SwDrawTextInfo &rInf );
|
|
|
|
/**
|
|
Two subtleties needs to be mentioned:
|
|
\li DrawRect() is allowed over the ClipRects
|
|
\li FlyToRect() returns bigger values than the frame data
|
|
|
|
Ensure that the overlapping frames (except the transparent frames)
|
|
won't be scribbled
|
|
*/
|
|
void DrawFlyRect( OutputDevice* pOut, const SwRect &rRect );
|
|
|
|
/**
|
|
Used to switch off the SwTextFly when there is no overlapping object (Relax).
|
|
|
|
\param[in] the line area
|
|
\return whether the line will be overlapped by a frame
|
|
*/
|
|
bool IsAnyFrame( const SwRect &rLine ) const;
|
|
|
|
/**
|
|
Same as IsAnyFrame(const SwRect&), but uses the current frame print
|
|
area
|
|
*/
|
|
bool IsAnyFrame() const;
|
|
|
|
/**
|
|
true when a frame or DrawObj must be taken in account. The optimizations
|
|
like Paint/FormatEmpty for empty sentences or the virtual OutputDevice can
|
|
be used only when false is returned.
|
|
|
|
\param rRect
|
|
The rectangle can be empty, the current frame is then used. The value is
|
|
global to the document.
|
|
*/
|
|
bool IsAnyObj( const SwRect& rRect ) const;
|
|
|
|
void SetIgnoreCurrentFrame( bool bNew );
|
|
void SetIgnoreContour( bool bNew );
|
|
|
|
void SetIgnoreObjsInHeaderFooter( const bool bNew );
|
|
|
|
SwRect GetFrameArea() const;
|
|
};
|
|
|
|
inline SwAnchoredObjList& SwTextFly::GetAnchoredObjList() const
|
|
{
|
|
return mpAnchoredObjList
|
|
? *mpAnchoredObjList
|
|
: const_cast<SwTextFly*>(this)->InitAnchoredObjList();
|
|
}
|
|
|
|
inline void SwTextFly::SetTopRule()
|
|
{
|
|
m_bTopRule = false;
|
|
}
|
|
|
|
inline bool SwTextFly::IsOn() const
|
|
{
|
|
return m_bOn;
|
|
}
|
|
|
|
inline bool SwTextFly::Relax( const SwRect &rRect )
|
|
{
|
|
if (m_bOn)
|
|
{
|
|
m_bOn = IsAnyFrame( rRect );
|
|
}
|
|
return m_bOn;
|
|
}
|
|
|
|
inline bool SwTextFly::Relax()
|
|
{
|
|
if (m_bOn)
|
|
{
|
|
m_bOn = IsAnyFrame();
|
|
}
|
|
return m_bOn;
|
|
}
|
|
|
|
inline SwTwips SwTextFly::GetMinBottom() const
|
|
{
|
|
return mpAnchoredObjList ? m_nMinBottom : CalcMinBottom();
|
|
}
|
|
|
|
inline const SwTextFrame* SwTextFly::GetMaster() const
|
|
{
|
|
return m_pMaster ? m_pMaster : const_cast<SwTextFly*>(this)->GetMaster_();
|
|
}
|
|
|
|
inline tools::Long SwTextFly::GetNextTop() const
|
|
{
|
|
return m_nNextTop;
|
|
}
|
|
|
|
inline void SwTextFly::SetNextTop( tools::Long nNew ) const
|
|
{
|
|
const_cast<SwTextFly*>(this)->m_nNextTop = nNew;
|
|
}
|
|
|
|
inline SwRect SwTextFly::GetFrame( const SwRect &rRect ) const
|
|
{
|
|
return m_bOn ? GetFrame_( rRect ) : SwRect();
|
|
}
|
|
|
|
inline void SwTextFly::SetIgnoreCurrentFrame( bool bNew )
|
|
{
|
|
mbIgnoreCurrentFrame = bNew;
|
|
}
|
|
|
|
inline void SwTextFly::SetIgnoreContour( bool bNew )
|
|
{
|
|
mbIgnoreContour = bNew;
|
|
}
|
|
|
|
inline void SwTextFly::SetIgnoreObjsInHeaderFooter( const bool bNew )
|
|
{
|
|
mbIgnoreObjsInHeaderFooter = bNew;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|