1 /* AbiWord
2  * Copyright (C) 1998 AbiSource, Inc.
3  * Copyright (C) 2002 Patrick Lam <plam@mit.edu>
4  * Copyright (C) 2003 Martin Sevior <msevior@physics.unimelb.edu.au>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 #include <stdlib.h>
23 #include <math.h>
24 #include <string.h>
25 
26 #include "fp_FrameContainer.h"
27 #include "fp_Column.h"
28 #include "fp_Page.h"
29 #include "fp_Line.h"
30 #include "fl_DocLayout.h"
31 #include "pd_Document.h"
32 #include "fl_SectionLayout.h"
33 #include "gr_DrawArgs.h"
34 #include "ut_vector.h"
35 #include "ut_types.h"
36 #include "ut_debugmsg.h"
37 #include "ut_assert.h"
38 #include "fl_FrameLayout.h"
39 #include "fp_TableContainer.h"
40 #include "fv_View.h"
41 #include "gr_Painter.h"
42 #include "fl_BlockLayout.h"
43 
44 /*!
45   Create Frame container
46   \param iType Container type
47   \param pSectionLayout Section layout type used for this container
48  */
fp_FrameContainer(fl_SectionLayout * pSectionLayout)49 fp_FrameContainer::fp_FrameContainer(fl_SectionLayout* pSectionLayout)
50 	: fp_VerticalContainer(FP_CONTAINER_FRAME, pSectionLayout),
51 	  m_pPage(NULL),
52 	  m_iXpad(0),
53 	  m_iYpad(0),
54 	  m_bNeverDrawn(true),
55 	  m_bOverWrote(false),
56 	  m_bIsWrapped(false),
57 	  m_bIsTightWrapped(false),
58 	  m_bIsAbove(true),
59 	  m_bIsTopBot(false),
60 	  m_bIsLeftWrapped(false),
61 	  m_bIsRightWrapped(false),
62 	  m_iPreferedPageNo(-1),
63 	  m_iPreferedColumnNo(0)
64 {
65 }
66 
67 /*!
68   Destruct container
69   \note The Containers in vector of the container are not
70         destructed. They are owned by the logical hierarchy (i.e.,
71 		the fl_Container classes like fl_BlockLayout), not the physical
72         hierarchy.
73  */
~fp_FrameContainer()74 fp_FrameContainer::~fp_FrameContainer()
75 {
76   UT_DEBUGMSG(("Delete FrameContainer %p \n",this));
77 	m_pPage = NULL;
78 }
79 
setPage(fp_Page * pPage)80 void fp_FrameContainer::setPage(fp_Page * pPage)
81 {
82 	if(pPage && (m_pPage != NULL) && m_pPage != pPage)
83 	{
84 		clearScreen();
85 		m_pPage->removeFrameContainer(this);
86 		getSectionLayout()->markAllRunsDirty();
87 
88 		UT_GenericVector<fl_ContainerLayout *> AllLayouts;
89 		AllLayouts.clear();
90 		m_pPage->getAllLayouts(AllLayouts);
91 		UT_sint32 i = 0;
92 		for(i=0; i<AllLayouts.getItemCount(); i++)
93 		{
94 		      fl_ContainerLayout * pCL = AllLayouts.getNthItem(i);
95 		      pCL->collapse();
96 		      pCL->format();
97 	        }
98 		m_pPage->getOwningSection()->setNeedsSectionBreak(true,m_pPage);
99 
100 	}
101 	m_pPage = pPage;
102 	if(pPage)
103 	{
104 		getFillType().setParent(&pPage->getFillType());
105 	}
106 	else
107 	{
108 		getFillType().setParent(NULL);
109 	}
110 }
111 
112 
isAbove(void)113 bool fp_FrameContainer::isAbove(void)
114 {
115   return  m_bIsAbove;
116 }
117 /*!
118  * Returns true if the supplied screen rectangle overlaps with frame
119  * container. This method takes account of transparening and tight wrapping.
120  */
overlapsRect(UT_Rect & rec)121 bool fp_FrameContainer::overlapsRect(UT_Rect & rec)
122 {
123      UT_Rect * pMyFrameRec = getScreenRect();
124      fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
125      UT_sint32 iextra = pFL->getBoundingSpace() -2;
126      pMyFrameRec->left -= iextra;
127      pMyFrameRec->top -= iextra;
128      pMyFrameRec->width += 2*iextra;
129      pMyFrameRec->height += 2*iextra;
130      xxx_UT_DEBUGMSG(("look at rec.left %d top %d width %d  \n",rec.left,rec.top,rec.width));
131      if(rec.intersectsRect(pMyFrameRec))
132      {
133          if(!isTightWrapped())
134 	 {
135 	      delete pMyFrameRec;
136 	      return true;
137 	 }
138 	 UT_sint32 iTweak = getGraphics()->tlu(2);
139 	 pMyFrameRec->left += iextra + iTweak;
140 	 pMyFrameRec->top += iextra + iTweak;
141 	 pMyFrameRec->width -= (2*iextra + 2*iTweak);
142 	 pMyFrameRec->height -= (2*iextra + 2*iTweak);
143 
144 	 UT_sint32 y = rec.top - pMyFrameRec->top;
145 	 UT_sint32 h = rec.height;
146 	 if(pFL->getBackgroundImage() == NULL)
147 	 {
148 	      delete pMyFrameRec;
149 	      return true;
150 	 }
151 	 UT_sint32 pad = pFL->getBoundingSpace();
152 	 UT_sint32 iLeft = pFL->getBackgroundImage()->GetOffsetFromLeft(getGraphics(),pad,y,h);
153 	 xxx_UT_DEBUGMSG(("iLeft projection %d \n",iLeft));
154 	 if(iLeft < -getWidth())
155 	 {
156 	   //
157 	   // Pure transparent.
158 	   //
159 	   xxx_UT_DEBUGMSG(("Overlaps pure transparent line top %d line height %d image top %d \n",rec.top,rec.height,y));
160 	      delete pMyFrameRec;
161 	      return false;
162 	 }
163 	 xxx_UT_DEBUGMSG(("iLeft in overlapRect %d Y %d \n",iLeft,y));
164 	 if(rec.left < pMyFrameRec->left)
165 	 {
166               pMyFrameRec->left -= iLeft;
167 	      xxx_UT_DEBUGMSG(("Moves Image left border by %d to %d \n",-iLeft,pMyFrameRec->left));
168 	 }
169 	 else
170 	 {
171 	      UT_sint32 iRight = pFL->getBackgroundImage()->GetOffsetFromRight(getGraphics(),pad,y,h);
172               pMyFrameRec->width += iRight;
173 	      xxx_UT_DEBUGMSG(("Reduce Image width by %d to %d \n",iRight,pMyFrameRec->width));
174 	 }
175 	 if(rec.intersectsRect(pMyFrameRec))
176 	 {
177 	   xxx_UT_DEBUGMSG(("Frame Still overlaps \n"));
178 	   delete pMyFrameRec;
179 	   return true;
180 	 }
181 	 xxx_UT_DEBUGMSG(("Tight Frame no longer overlaps \n"));
182 	 xxx_UT_DEBUGMSG(("Line Top %d Height %d left %d width %d \n",rec.top,rec.height,rec.left,rec.width));
183 	 xxx_UT_DEBUGMSG(("Image Top %d Height %d left %d width %d \n",pMyFrameRec->top,pMyFrameRec->height,pMyFrameRec->left,pMyFrameRec->width));
184 	 xxx_UT_DEBUGMSG(("Relative Top of line %d \n",y));
185      }
186      delete pMyFrameRec;
187      return false;
188 }
189 
setPreferedPageNo(UT_sint32 i)190 void fp_FrameContainer::setPreferedPageNo(UT_sint32 i)
191 {
192      if(m_iPreferedPageNo == i)
193        return;
194      m_iPreferedPageNo =  i;
195      fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
196      FL_DocLayout * pDL = pFL->getDocLayout();
197      if(pDL->isLayoutFilling())
198        return;
199      PD_Document * pDoc = pDL->getDocument();
200      UT_UTF8String sVal;
201      UT_UTF8String_sprintf(sVal,"%d",i);
202      const char * attr = PT_PROPS_ATTRIBUTE_NAME;
203      UT_UTF8String sAttVal = "frame-pref-page:";
204      sAttVal += sVal.utf8_str();
205 
206      pDoc->changeStruxAttsNoUpdate(pFL->getStruxDocHandle(),attr,sAttVal.utf8_str());
207 }
208 
setPreferedColumnNo(UT_sint32 i)209 void fp_FrameContainer::setPreferedColumnNo(UT_sint32 i)
210 {
211      if(m_iPreferedColumnNo == i)
212        return;
213      m_iPreferedColumnNo =  i;
214      fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
215      FL_DocLayout * pDL = pFL->getDocLayout();
216      if(pDL->isLayoutFilling())
217        return;
218      PD_Document * pDoc = pDL->getDocument();
219      UT_UTF8String sVal;
220      UT_UTF8String_sprintf(sVal,"%d",i);
221      const char * attr = PT_PROPS_ATTRIBUTE_NAME;
222      UT_UTF8String sAttVal = "frame-pref-column:";
223      sAttVal += sVal.utf8_str();
224 
225      pDoc->changeStruxAttsNoUpdate(pFL->getStruxDocHandle(),attr,sAttVal.utf8_str());
226 }
227 
228 /*!
229  * This method returns the padding to be applied between a line approaching
230  * wrapped frame or image from the left.
231  * y Is the top of the line in logical units as defined relative to the
232  * y position on the screen.
233  * height is the height of the line.
234  * If tight wrapping is set on a positioned object this number can be negative
235  * which means the line can encroach into the rectangular region of the
236  * image provided the region is transparent.
237  */
getLeftPad(UT_sint32 y,UT_sint32 height)238 UT_sint32 fp_FrameContainer::getLeftPad(UT_sint32 y, UT_sint32 height)
239 {
240   fl_FrameLayout *pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
241   UT_sint32 pad = pFL->getBoundingSpace();
242   UT_Rect * pRect = getScreenRect();
243   UT_sint32 yC = pRect->top;
244   delete pRect;
245   if(!isTightWrapped() || !isWrappingSet())
246   {
247     return pad;
248   }
249   if(FL_FRAME_TEXTBOX_TYPE == pFL->getFrameType())
250   {
251     return pad;
252   }
253   if(pFL->getBackgroundImage() == NULL)
254   {
255     return pad;
256   }
257   UT_sint32 iLeft = pFL->getBackgroundImage()->GetOffsetFromLeft(getGraphics(),pad,y - yC,height);
258   xxx_UT_DEBUGMSG(("Local Y %d iLeft %d width %d \n",y-yC,iLeft,getFullWidth()));  return iLeft;
259 }
260 
261 
262 /*!
263  * This method returns the padding to be applied between a line approaching
264  * wrapped frame or image from the right.
265  * y Is the top of the line in logical units as defined relative to the
266  * y position on the screen.
267  * height is the height of the line.
268  * If tight wrapping is set on a positioned object this number can be negative
269  * which means the line can encroach into the rectangular region of the
270  * image provided the region is transparent.
271  */
getRightPad(UT_sint32 y,UT_sint32 height)272 UT_sint32 fp_FrameContainer::getRightPad(UT_sint32 y, UT_sint32 height)
273 {
274   fl_FrameLayout *pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
275   UT_sint32 pad = pFL->getBoundingSpace();
276   UT_Rect * pRect = getScreenRect();
277   UT_sint32 yC = pRect->top;
278   if(!isTightWrapped() || !isWrappingSet())
279   {
280     return pad;
281   }
282   if(FL_FRAME_TEXTBOX_TYPE == pFL->getFrameType())
283   {
284     return pad;
285   }
286   if(pFL->getBackgroundImage() == NULL)
287   {
288     return pad;
289   }
290   UT_sint32 iRight = pFL->getBackgroundImage()->GetOffsetFromRight(getGraphics(),pad,y - yC,height);
291   xxx_UT_DEBUGMSG(("Local Y %d iRight %d width %d \n",y-yC,iRight,getFullWidth()));
292   return iRight;
293 }
294 
clearScreen(void)295 void fp_FrameContainer::clearScreen(void)
296 {
297 	fp_Page * pPage = getPage();
298 	if(pPage == NULL)
299 	{
300 		return;
301 	}
302 	if(getView() == NULL)
303 	{
304 		return;
305 	}
306 
307 	UT_sint32 srcX,srcY;
308 	UT_sint32 xoff,yoff;
309 	getView()->getPageScreenOffsets(pPage,xoff,yoff);
310 	xxx_UT_DEBUGMSG(("pagescreenoffsets xoff %d yoff %d \n",xoff,yoff));
311 	UT_sint32 leftThick = m_lineLeft.m_thickness;
312 	UT_sint32 rightThick = m_lineRight.m_thickness;
313 	UT_sint32 topThick = m_lineTop.m_thickness;
314 	UT_sint32 botThick = m_lineBottom.m_thickness;
315 
316 	srcX = getFullX() - leftThick;
317 	srcY = getFullY() - topThick;
318 
319 	xoff += getFullX() - leftThick;
320 	yoff += getFullY() - topThick;
321 	getFillType().getParent()->Fill(getGraphics(),srcX,srcY,xoff,yoff,getFullWidth()+leftThick+rightThick,getFullHeight()+topThick+botThick+getGraphics()->tlu(1) +1);
322 	fp_Container * pCon = NULL;
323 	UT_sint32 i = 0;
324 	for(i=0; i< countCons(); i++)
325 	{
326 		pCon = static_cast<fp_Container *>(getNthCon(i));
327 		pCon->clearScreen();
328 	}
329 	m_bNeverDrawn = true;
330 }
331 
332 /*!
333  * All these methods are used to implement an X and Y padding around the
334  * Frame
335  */
getFullWidth(void) const336 UT_sint32 fp_FrameContainer::getFullWidth(void) const
337 {
338 	return fp_VerticalContainer::getWidth();
339 }
340 
getFullHeight(void) const341 UT_sint32 fp_FrameContainer::getFullHeight(void) const
342 {
343 	return fp_VerticalContainer::getHeight();
344 }
345 
getFullX(void) const346 UT_sint32 fp_FrameContainer::getFullX(void) const
347 {
348 	return fp_VerticalContainer::getX();
349 }
350 
getFullY(void) const351 UT_sint32 fp_FrameContainer::getFullY(void) const
352 {
353 	return fp_VerticalContainer::getY();
354 }
355 
356 
getWidth(void) const357 UT_sint32 fp_FrameContainer::getWidth(void) const
358 {
359 	UT_sint32 iWidth = fp_VerticalContainer::getWidth() - m_iXpad*2;
360 	return iWidth;
361 }
362 
getX(void) const363 UT_sint32 fp_FrameContainer::getX(void) const
364 {
365 	UT_sint32 iX = fp_VerticalContainer::getX() + m_iXpad;
366 	return iX;
367 }
368 
369 
getY(void) const370 UT_sint32 fp_FrameContainer::getY(void) const
371 {
372 	UT_sint32 iY = fp_VerticalContainer::getY() + m_iYpad;
373 	return iY;
374 }
375 
getHeight(void) const376 UT_sint32 fp_FrameContainer::getHeight(void) const
377 {
378 	UT_sint32 iHeight = fp_VerticalContainer::getHeight() - m_iYpad*2;
379 	return iHeight;
380 }
381 
382 
setContainer(fp_Container *)383 void fp_FrameContainer::setContainer(fp_Container * /*pContainer*/)
384 {
385 	UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
386 }
387 
getDocSectionLayout(void)388 fl_DocSectionLayout * fp_FrameContainer::getDocSectionLayout(void)
389 {
390 	fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
391 	fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pFL->getSectionLayout());
392 	UT_ASSERT(pDSL && (pDSL->getContainerType() == FL_CONTAINER_DOCSECTION));
393 	return pDSL;
394 }
395 
396 /*!
397  * Fill the supplied vector with a list of the blocks whose lines are affected
398  * by the Frame.
399  */
getBlocksAroundFrame(UT_GenericVector<fl_BlockLayout * > & vecBlocks)400 void fp_FrameContainer::getBlocksAroundFrame(UT_GenericVector<fl_BlockLayout *> & vecBlocks)
401 {
402   fp_Page * pPage = getPage();
403   if(pPage == NULL)
404   {
405     return;
406   }
407   UT_sint32 iColLeader = 0;
408   fp_Column * pCol = NULL;
409   fl_BlockLayout * pCurBlock = NULL;
410   fp_Line * pCurLine = NULL;
411   fp_Container * pCurCon = NULL;
412   if(pPage->countColumnLeaders() == 0)
413   {
414       UT_sint32 iPage = getPreferedPageNo();
415       if(iPage >0)
416           setPreferedPageNo(iPage-1);
417       return;
418   }
419   for(iColLeader = 0; iColLeader < pPage->countColumnLeaders(); iColLeader++)
420   {
421       pCol = pPage->getNthColumnLeader(iColLeader);
422       while(pCol)
423       {
424           UT_sint32 i = 0;
425           UT_sint32 iYCol = pCol->getY(); // Vertical position relative to page.
426           for(i=0; i< pCol->countCons(); i++)
427           {
428               pCurCon = static_cast<fp_Container *>(pCol->getNthCon(i));
429               if(pCurCon->getContainerType() == FP_CONTAINER_LINE)
430               {
431                   pCurLine = static_cast<fp_Line *>(pCurCon);
432                   UT_sint32 iYLine = iYCol + pCurLine->getY();
433                   xxx_UT_DEBUGMSG(("iYLine %d FullY %d FullHeight %d \n",iYLine,getFullY(),getFullHeight()));
434                   if((iYLine + pCurLine->getHeight() > getFullY()) && (iYLine < (getFullY() + getFullHeight())))
435                   {
436                       //
437                       // Line overlaps frame in Height. Add it's block to the vector.
438                       //
439                       if(pCurLine->getBlock() != pCurBlock)
440                       {
441                           pCurBlock = pCurLine->getBlock();
442                           vecBlocks.addItem(pCurBlock);
443                           xxx_UT_DEBUGMSG(("Add Block %x to vector \n",pCurBlock));
444                       }
445                   }
446               }
447           }
448           pCol = pCol->getFollower();
449       }
450   }
451   if(vecBlocks.getItemCount() == 0)
452   {
453       pCol = pPage->getNthColumnLeader(0);
454       fp_Container * pCon = pCol->getFirstContainer();
455       fl_BlockLayout * pB = NULL;
456       if(pCon && pCon->getContainerType() == FP_CONTAINER_LINE)
457       {
458           pB = static_cast<fp_Line *>(pCon)->getBlock();
459       }
460       else if(pCon)
461       {
462           fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pCon->getSectionLayout());
463           pB = pCL->getNextBlockInDocument();
464       }
465       if(pB != NULL)
466           vecBlocks.addItem(pB);
467   }
468 
469 }
470 
471 /* just a little helper function
472  */
_drawLine(const PP_PropertyMap::Line & style,UT_sint32 left,UT_sint32 top,UT_sint32 right,UT_sint32 bot,GR_Graphics * pGr)473 void fp_FrameContainer::_drawLine (const PP_PropertyMap::Line & style,
474 								  UT_sint32 left, UT_sint32 top, UT_sint32 right, UT_sint32 bot,GR_Graphics * pGr)
475 {
476 	GR_Painter painter(pGr);
477 
478 	if (style.m_t_linestyle == PP_PropertyMap::linestyle_none)
479 		return; // do not draw
480 
481 	GR_Graphics::JoinStyle js = GR_Graphics::JOIN_MITER;
482 	GR_Graphics::CapStyle  cs = GR_Graphics::CAP_PROJECTING;
483 
484 	UT_sint32 iLineWidth = static_cast<UT_sint32>(style.m_thickness);
485 	pGr->setLineWidth (iLineWidth);
486 	pGr->setColor (style.m_color);
487 
488 	switch (style.m_t_linestyle)
489 	{
490 		case PP_PropertyMap::linestyle_dotted:
491 			pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_DOTTED);
492 			break;
493 		case PP_PropertyMap::linestyle_dashed:
494 			pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_ON_OFF_DASH);
495 			break;
496 		case PP_PropertyMap::linestyle_solid:
497 			pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_SOLID);
498 			break;
499 		default: // do nothing; shouldn't happen
500 			break;
501 	}
502 
503 	xxx_UT_DEBUGMSG(("_drawLine: top %d bot %d \n",top,bot));
504 
505 	painter.drawLine (left, top, right, bot);
506 
507 	pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_SOLID);
508 }
509 
510 /*!
511  * Draw the frame boundaries
512  */
drawBoundaries(dg_DrawArgs * pDA)513 void  fp_FrameContainer::drawBoundaries(dg_DrawArgs * pDA)
514 {
515 	UT_sint32 iXlow = pDA->xoff - m_iXpad;
516 	UT_sint32 iXhigh = iXlow + getFullWidth() ;
517 	UT_sint32 iYlow = pDA->yoff - m_iYpad;
518 	UT_sint32 iYhigh = iYlow + getFullHeight();
519 	GR_Graphics * pG = pDA->pG;
520 	if(getPage())
521 	{
522 		getPage()->expandDamageRect(iXlow,iYlow,getFullWidth(),getFullHeight());
523 
524 		//
525 		// Only fill to the bottom of the viewed page.
526 		//
527 		UT_sint32 iFullHeight = getFullHeight();
528 		fl_DocSectionLayout * pDSL = getDocSectionLayout();
529 		UT_sint32 iMaxHeight = 0;
530 		if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (getView()->getViewMode() != VIEW_PRINT))
531 		{
532 		        iMaxHeight = pDSL->getActualColumnHeight();
533 		}
534 		else
535 		{
536 		        iMaxHeight = getPage()->getHeight();
537 		}
538 		UT_sint32 iBot = getFullY()+iFullHeight;
539 		if(iBot > iMaxHeight)
540 		{
541 		        iFullHeight = iFullHeight - (iBot-iMaxHeight);
542 			iYhigh = iFullHeight;
543 		}
544 	}
545 	_drawLine(m_lineTop,iXlow,iYlow,iXhigh,iYlow,pDA->pG); // top
546 	_drawLine(m_lineRight,iXhigh,iYlow,iXhigh,iYhigh,pDA->pG); // right
547 	_drawLine(m_lineBottom,iXlow,iYhigh,iXhigh,iYhigh,pDA->pG); // bottom
548 	_drawLine(m_lineLeft,iXlow,iYlow,iXlow,iYhigh,pDA->pG); // left
549 }
550 
551 
552 /*!
553  * Draw the frame handles
554  */
drawHandles(dg_DrawArgs * pDA)555 void  fp_FrameContainer::drawHandles(dg_DrawArgs * pDA)
556 {
557         if(getView() == NULL)
558 	{
559 	     getSectionLayout()->format();
560 	     getSectionLayout()->setNeedsReformat(getSectionLayout());
561 	}
562         if(getView() == NULL)
563 	{
564 	     return;
565 	}
566 	if(!getPage())
567 	{
568 	     return;
569 	}
570 	//
571 	// Only fill to the bottom of the viewed page.
572 	//
573 	GR_Graphics * pG = pDA->pG;
574 	UT_sint32 iFullHeight = getFullHeight();
575 	fl_DocSectionLayout * pDSL = getDocSectionLayout();
576 	UT_sint32 iMaxHeight = 0;
577 	if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (getView()->getViewMode() != VIEW_PRINT))
578 	{
579 	    iMaxHeight = pDSL->getActualColumnHeight();
580 	}
581 	else
582 	{
583 	    iMaxHeight = getPage()->getHeight();
584 	}
585 	UT_sint32 iBot = getFullY()+iFullHeight;
586 	if(iBot > iMaxHeight)
587 	{
588 	    iFullHeight = iFullHeight - (iBot-iMaxHeight);
589 	}
590 	UT_sint32 iXlow = pDA->xoff - m_iXpad;
591 	UT_sint32 iYlow = pDA->yoff - m_iYpad;
592 
593 	UT_Rect box(iXlow + pDA->pG->tlu(2), iYlow + pDA->pG->tlu(2), getFullWidth() - pDA->pG->tlu(4), iFullHeight - pDA->pG->tlu(4));
594 	getPage()->expandDamageRect(box.left,box.top,box.width,box.height);
595 	getView()->drawSelectionBox(box, true);
596 }
597 
598 /*!
599  Draw container content
600  \param pDA Draw arguments
601  */
draw(dg_DrawArgs * pDA)602 void fp_FrameContainer::draw(dg_DrawArgs* pDA)
603 {
604 	FV_View * pView = getView();
605 	UT_return_if_fail( pView);
606 
607 	xxx_UT_DEBUGMSG(("FrameContainer %x called, page %x \n",this,getPage()));
608 	if(getPage() == NULL)
609 	{
610 	     getSectionLayout()->format();
611 	     getSectionLayout()->setNeedsReformat(getSectionLayout());
612 	     if(getPage() == NULL)
613 	     {
614 			 return;
615 	     }
616 	}
617 	if(pView)
618 	{
619 		if(pView->getFrameEdit()->getFrameEditMode() == FV_FrameEdit_DRAG_EXISTING)
620 		{
621 			if((pView->getFrameEdit()->getFrameContainer() == this))
622 			{
623 				return;
624 			}
625 		}
626 	}
627 //
628 // Only draw the lines in the clipping region.
629 //
630 /*
631 	[Somewhere down here is where the logic to only draw the region of the frame which
632 	is within the complement of the union of all higher frames needs to be. We need to
633 	draw the applicable region of the rectangle we're on, then unify it with (if
634 	applicable) the higher union.] <-- Possibly obsolete comment, not sure.
635 	I think I might have landed on an alternative solution involving more rearranging
636 	of the storage of the FrameContainers, based on their z-index.  Not sure how far
637 	I got with that or if it worked either.  See also abi bug 7664 and the original
638 	discussions about defining the undefinedness of layered frame behaviour.
639 */
640 
641 	if(m_bOverWrote)
642 	{
643 		pDA->bDirtyRunsOnly = false;
644 	}
645 	dg_DrawArgs da = *pDA;
646 	GR_Graphics * pG = da.pG;
647 	UT_return_if_fail( pG);
648 
649 	UT_sint32 x = pDA->xoff - m_iXpad;
650 	UT_sint32 y = pDA->yoff - m_iYpad;
651 	getPage()->expandDamageRect(x,y,getFullWidth(),getFullHeight());
652 	if(!pDA->bDirtyRunsOnly || m_bNeverDrawn)
653 	{
654 		if(m_bNeverDrawn)
655 		{
656 			pDA->bDirtyRunsOnly= false;
657 		}
658 		UT_sint32 srcX,srcY;
659 		getSectionLayout()->checkGraphicTick(pG);
660 		srcX = -m_iXpad;
661 		srcY = -m_iYpad;
662 		//
663 		// Only fill to the bottom of the viewed page.
664 		//
665 		UT_sint32 iFullHeight = getFullHeight();
666 		fl_DocSectionLayout * pDSL = getDocSectionLayout();
667 		UT_sint32 iMaxHeight = 0;
668 		if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (pView->getViewMode() != VIEW_PRINT))
669 		{
670 		        iMaxHeight = pDSL->getActualColumnHeight();
671 		}
672 		else
673 		{
674 		        iMaxHeight = getPage()->getHeight();
675 		}
676 		UT_sint32 iBot = getFullY()+iFullHeight;
677 		if(iBot > iMaxHeight)
678 		{
679 		        iFullHeight = iFullHeight - (iBot-iMaxHeight);
680 		}
681 		getFillType().Fill(pG,srcX,srcY,x,y,getFullWidth(),iFullHeight);
682 		m_bNeverDrawn = false;
683 	}
684 	UT_uint32 count = countCons();
685 	xxx_UT_DEBUGMSG(("Number of containers in frame %d \n",count));
686 	auto p = pDA->pG->getClipRect();
687 	std::unique_ptr<UT_Rect> pPrevRect(p ? new UT_Rect(*p) : nullptr);
688 	UT_Rect * pRect = getScreenRect();
689 	UT_Rect newRect;
690 	bool bRemoveRectAfter = false;
691 	bool bSetOrigClip = false;
692 	bool bSkip = false;
693 	if((pPrevRect == NULL) && pG->queryProperties(GR_Graphics::DGP_SCREEN))
694 	{
695 		pDA->pG->setClipRect(pRect);
696 		UT_DEBUGMSG(("Clip bottom is %d \n",pRect->top + pRect->height));
697 		bRemoveRectAfter = true;
698 	}
699 	else if(pPrevRect && !pRect->intersectsRect(pPrevRect.get()))
700 	{
701 		bSkip = true;
702 		xxx_UT_DEBUGMSG(("External Clip bottom is %d \n",pRect->top + pRect->height));
703 	}
704 	else if(pPrevRect)
705 	{
706 		newRect.top = UT_MAX(pPrevRect->top,pRect->top);
707 		UT_sint32 iBotPrev = pPrevRect->height + pPrevRect->top;
708 		UT_sint32 iBot = pRect->height + pRect->top;
709 		newRect.height = UT_MIN(iBotPrev,iBot) - newRect.top;
710 		newRect.width = pPrevRect->width;
711 		newRect.left = pPrevRect->left;
712 		if((newRect.height > 0) && pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
713 		{
714 			pDA->pG->setClipRect(&newRect);
715 			bSetOrigClip = true;
716 		}
717 		else
718 		{
719 			bSkip = true;
720 		}
721 	}
722 	if(!bSkip)
723 	{
724 		for (UT_uint32 i = 0; i<count; i++)
725 		{
726 			fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
727 			da.xoff = pDA->xoff + pContainer->getX();
728 			da.yoff = pDA->yoff + pContainer->getY();
729 			pContainer->draw(&da);
730 		}
731 	}
732 	m_bNeverDrawn = false;
733 	m_bOverWrote = false;
734 	if(bRemoveRectAfter)
735 	{
736 		pDA->pG->setClipRect(NULL);
737 	}
738 	if(bSetOrigClip)
739 	{
740 		pDA->pG->setClipRect(pPrevRect.get());
741 	}
742 	delete pRect;
743 	drawBoundaries(pDA);
744 }
745 
setBackground(const PP_PropertyMap::Background & style)746 void fp_FrameContainer::setBackground (const PP_PropertyMap::Background & style)
747 {
748 	m_background = style;
749 	PP_PropertyMap::Background background = m_background;
750 	if(background.m_t_background == PP_PropertyMap::background_solid)
751 	{
752 		getFillType().setColor(background.m_color);
753 	}
754 }
755 
756 
757 /*!
758  * FrameContainers are not in the linked list of physical containers
759  */
getNextContainerInSection() const760 fp_Container * fp_FrameContainer::getNextContainerInSection() const
761 {
762 	return NULL;
763 }
764 
765 /*!
766  * FrameContainers are not in the linked list of physical containers
767  */
getPrevContainerInSection() const768 fp_Container * fp_FrameContainer::getPrevContainerInSection() const
769 {
770 	return NULL;
771 }
772 
layout(void)773 void fp_FrameContainer::layout(void)
774 {
775 	_setMaxContainerHeight(0);
776 	UT_sint32 iY = 0, iPrevY = 0;
777 	iY= 0;
778 	UT_uint32 iCountContainers = countCons();
779 	fp_Container *pContainer, *pPrevContainer = NULL;
780 	for (UT_uint32 i=0; i < iCountContainers; i++)
781 	{
782 		pContainer = static_cast<fp_Container*>(getNthCon(i));
783 //
784 // This is to speedup redraws.
785 //
786 		if(pContainer->getHeight() > _getMaxContainerHeight())
787 			_setMaxContainerHeight(pContainer->getHeight());
788 
789 		if(pContainer->getY() != iY)
790 		{
791 			pContainer->clearScreen();
792 		}
793 		if(iY > getHeight())
794 		{
795 			pContainer->setY(-1000000);
796 		}
797 		else
798 		{
799 			pContainer->setY(iY);
800 		}
801 		UT_sint32 iContainerHeight = pContainer->getHeight();
802 		UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
803 		if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
804 		{
805 			fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
806 			iContainerHeight = pTab->getHeight();
807 			if(!pTab->isThisBroken() && (pTab->getFirstBrokenTable() == NULL))
808 			{
809 				/*fp_Container * pBroke = static_cast<fp_Container *> */(pTab->VBreakAt(0));
810 			}
811 		}
812 
813 		iY += iContainerHeight;
814 		iY += iContainerMarginAfter;
815 		//iY +=  0.5;
816 
817 		if (pPrevContainer)
818 		{
819 			pPrevContainer->setAssignedScreenHeight(iY - iPrevY);
820 		}
821 		pPrevContainer = pContainer;
822 		iPrevY = iY;
823 	}
824 
825 	// Correct height position of the last line
826 	if (pPrevContainer)
827 	{
828 		if(iY > getHeight())
829 		{
830 			pPrevContainer->setAssignedScreenHeight(-1000000);
831 		}
832 		else
833 		{
834 			pPrevContainer->setAssignedScreenHeight(iY - iPrevY + 1);
835 		}
836 	}
837 	fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
838 	if(pFL->expandHeight() && (iY > pFL->minHeight()))
839 	{
840 	     setHeight(iY+m_iYpad*2);
841 	}
842 }
843 
setHeight(UT_sint32 iY)844 void fp_FrameContainer::setHeight(UT_sint32 iY)
845 {
846         if(iY != getFullHeight())
847 	{
848 	     xxx_UT_DEBUGMSG((" SetHeight Frame iY %d Fullheight %d Height %d \n",iY,getFullHeight(),getHeight()));
849 	     clearScreen();
850 	     fp_VerticalContainer::setHeight(iY);
851 	     fp_Page * pPage = getPage();
852 	     getDocSectionLayout()->setNeedsSectionBreak(true,pPage);
853 	}
854 }
855