Class that represents a publication page that can be laid out.
상속: IPageInfo, IFWDisposable
예제 #1
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Inserts a new page after the given one.
		/// </summary>
		/// <param name="ypOffsetFromTopOfDiv">The offset from top of this division to the
		/// start of the page to insert.</param>
		/// <param name="pageToInsertAfter">The page to insert after.</param>
		/// <returns>The newly inserted page</returns>
		/// ------------------------------------------------------------------------------------
		private Page InsertPage(int ypOffsetFromTopOfDiv, Page pageToInsertAfter)
		{
			return m_publication.InsertPage(m_publication.IndexOfDiv(this), ypOffsetFromTopOfDiv,
				pageToInsertAfter);
		}
예제 #2
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Find the page following the given page. This is broken out as a method in case
		/// we decide to change to a linked list or something more complex.
		/// </summary>
		/// <param name="page"></param>
		/// <returns></returns>
		/// ------------------------------------------------------------------------------------
		public Page PageAfter(Page page)
		{
			CheckDisposed();

			int iPage = IndexOfPage(page) + 1;
			if (iPage >= m_pages.Count)
				return null;
			return m_pages[iPage];
		}
예제 #3
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Add the page element.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <param name="dysSpaceUsedOnPage">The amount of vertical space taken up by this
		/// element on this page.</param>
		/// <param name="currentColumn">The 1-based index of the current column.</param>
		/// <param name="numberColumns">The total number columns for the stream.</param>
		/// <param name="leftMargin">The left margin.</param>
		/// <param name="offsetFromTopOfDiv">The offset from top of division.</param>
		/// <param name="columnHeight">The height of the column.</param>
		/// <param name="dypOverlapWithPreviousElement"></param>
		/// ------------------------------------------------------------------------------------
		protected void AddElement(Page page, int dysSpaceUsedOnPage,
			int currentColumn, int numberColumns, int leftMargin,
			int offsetFromTopOfDiv, int columnHeight, int dypOverlapWithPreviousElement)
		{
			Debug.Assert(!page.IsDisposed);
			Rectangle rect = page.GetElementBounds(this, dysSpaceUsedOnPage, currentColumn,
				numberColumns, leftMargin, offsetFromTopOfDiv, columnHeight);

			page.AddPageElement(this, MainLayoutStream, false, rect, offsetFromTopOfDiv, true,
				currentColumn, numberColumns, ColumnGapWidthInPrinterPixels, columnHeight,
				dypOverlapWithPreviousElement, MainStreamIsRightToLeft, true);
		}
예제 #4
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Add page header and footer elements to the given page.
		/// </summary>
		/// <param name="page">The page to add the header to</param>
		/// <param name="xpLeftMargin">Left margin in printer pixels (we could recalc this, but
		/// since the caller already has it, it's faster to just pass it)</param>
		/// ------------------------------------------------------------------------------------
		private void AddHeaderAndFooter(Page page, int xpLeftMargin)
		{
			// Create the header stream
			IHeaderFooterConfigurer hfconfig = m_configurer.HFConfigurer;
			if (hfconfig == null)
			{
				// This configurer doesn't think we need headers and footers at all (test only?)
				return;
			}
			// TODO: re-use existing header/footer on page. Currently we create a new one
			// everytime we layout the page (e.g. after inserting a footnote).

			// TODO (TE-5845): If this is the first page in the division and this division starts
			// on a new page, treat it as the first page for the purpose of deciding which
			// PubHeaderFooter to use for laying out.
			int hvoHdrRoot = hfconfig.GetHvoRoot(page.PageNumber, true, m_fDifferentFirstHF,
				m_fDifferentEvenHF);
			if (hvoHdrRoot > 0)
			{
				int dypHdrHeight;
				var hfVc = hfconfig.MakeHeaderVc(page);
				m_CreatedHfVcs.Add(hfVc);
				IVwLayoutStream hdrStream = CreateHeaderOrFooter(hfVc,
					hvoHdrRoot, xpLeftMargin, m_dympHeaderPos, out dypHdrHeight);

				PublicationControl.SetAccessibleStreamName(hdrStream,
					Publication.AccessibleName + "_Header");

				// Add the header to the page's collection of elements
				int ypHeaderPosInPrinterPixels = (int)(m_dympHeaderPos *
					Publication.DpiYPrinter / MiscUtils.kdzmpInch) - dypHdrHeight;
				Rectangle locationOnPage = new Rectangle(xpLeftMargin,
					ypHeaderPosInPrinterPixels,
					AvailablePageWidthInPrinterPixels,
					dypHdrHeight);
				page.AddPageElement(this, hdrStream, true, locationOnPage, 0, false, 1, 1, 0,
					dypHdrHeight, 0, MainStreamIsRightToLeft, false);
			}
			int hvoFtrRoot = hfconfig.GetHvoRoot(page.PageNumber, false, m_fDifferentFirstHF,
				m_fDifferentEvenHF);
			if (hvoFtrRoot > 0)
			{
				int dypFtrHeight;
				var hfVc = hfconfig.MakeFooterVc(page);
				m_CreatedHfVcs.Add(hfVc);
				IVwLayoutStream ftrStream = CreateHeaderOrFooter(hfVc,
					hvoFtrRoot, xpLeftMargin, m_dympFooterPos, out dypFtrHeight);

				PublicationControl.SetAccessibleStreamName(ftrStream,
					Publication.AccessibleName + "_Footer");

				// Add the footer to the page's collection of elements
				int ypFooterPosInPrinterPixels = Publication.PageHeightInPrinterPixels -
					(int)(m_dympFooterPos * Publication.DpiYPrinter / MiscUtils.kdzmpInch);
				Rectangle locationOnPage = new Rectangle(xpLeftMargin,
					ypFooterPosInPrinterPixels,
					AvailablePageWidthInPrinterPixels,
					dypFtrHeight);
				page.AddPageElement(this, ftrStream, true, locationOnPage, 0, false, 1, 1, 0,
					dypFtrHeight, 0, MainStreamIsRightToLeft, false);
			}
		}
예제 #5
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Scroll the given or current selection into view.
		/// </summary>
		/// <param name="sel"></param>
		/// <param name="ssoFlag"></param>
		/// ------------------------------------------------------------------------------------
		public bool ScrollSelectionIntoView(IVwSelection sel, VwScrollSelOpts ssoFlag)
		{
			CheckDisposed();

			IVwSelection vwsel = sel;
			if (vwsel == null)
			{
				if (FocusedRootBox != null)
					vwsel = FocusedRootBox.Selection;
			}

			if (vwsel == null)
				return false; // nothing to do, no selection

			IVwGraphics vg = PrinterGraphics;
			try
			{
				// Loop until we have figured a scroll offset and confirmed the pages that
				// are visible there are laid out ready to draw.
				for (; ; )
				{
					// We pass this as source AND destination rectangle to get the selection
					// location relative to the whole document in printer coordinates.
//					Rect rcSrc = new Rect(0, 0, (int)DpiXPrinter, (int)DpiYPrinter);
					bool fEndBeforeAnchor;
					Rectangle rcSelPrinter;
					int clientWidthPrinter = ConvertScreenDistanceToPrinterX(ClientRectangle.Width,
						DpiXScreen);
					rcSelPrinter = GetSelectionRectangle(vwsel, vg, out fEndBeforeAnchor);
					// At this point, rcIdeal is a rectangle that we want on the screen, in
					// printer coordinates relative to the top of the document.
					IVwLayoutStream stream = (IVwLayoutStream)(vwsel.RootBox);
					int iDivTop; // index of division containing top of ideal rectangle
					int dysPageTopScreen; // top of page to top of rectangle in screen coords.
					bool layedOutPage;
					Page pageTop = PageFromPrinterY(rcSelPrinter.Left, rcSelPrinter.Top, false, stream,
						out dysPageTopScreen, out iDivTop, out layedOutPage);
					if (layedOutPage)
						continue;
					int iDivBottom; // index of division containing bottom of ideal rectangle
					int dysPageBottomScreen; // top of page to bottom of rectangle in screen coords.
					Page pageBottom = PageFromPrinterY(rcSelPrinter.Right, rcSelPrinter.Bottom, true, stream,
						out dysPageBottomScreen, out iDivBottom, out layedOutPage);
					if (layedOutPage)
						continue;
					// Enhance: this happens when moving within a secondary stream when the page that
					// will eventually contain the footnote (or whatever) has not been laid out.
					// This generic code has no idea which page will eventually contain the anchor for
					// this object.
					// Options:
					// 1. Leave it like this...fail to make the selection visible. (Maybe dialog?)
					// 2. Create real pages sequentially through the document until PageFromPrinterY
					//	succeeds. (This might take a while!).
					// 3. Make use of a virtual function, the default version of which fails,
					//	which can be asked, given a selection in a secondary stream, for a selection at
					//	the corresponding anchor. (This might be useful for other purposes...could be a
					//	method of the configurer.) Then we lay out the page that contains the anchor,
					//	after which we should be able to retry PageFromPrinterY successfully.
					if (pageTop == null || pageBottom == null)
						return false;
					// If those aren't properly laid-out pages, make them so and try again.
					// We repeat all the logic, because making them real may have expanded lazy
					// boxes and invalidated all the positions we worked out.
					// The process must terminate, because eventually (in a worst case) all pages are
					// laid out, all lazy boxes expanded. In practice it should terminate much sooner.
					if (EnsureRealBoxAt(pageTop) || EnsureRealBoxAt(pageBottom))
						continue;
					Page oldPageBeingLaidOut = m_pageBeingLaidOut;
					try
					{
						m_pageBeingLaidOut = pageTop;
						if (pageTop.LayOutIfNeeded())
							continue;
						m_pageBeingLaidOut = pageBottom;
						if (pageBottom.LayOutIfNeeded())
							continue;
					}
					finally
					{
						// We need to restore the page that was being laid out if we got here
						// during a layout in another place like PrepareToDrawPages()
						m_pageBeingLaidOut = oldPageBeingLaidOut;
					}
					int indexOfTopPage = IndexOfPage(pageTop);
					int indexOfBottomPage = indexOfTopPage;
					if (pageTop != pageBottom)
						indexOfBottomPage = IndexOfPage(pageBottom);
					int ysTopOfTopPageScreen = indexOfTopPage * PageHeightPlusGapInScreenPixels;
					int ysTopOfBottomPageScreen = indexOfBottomPage *
						PageHeightPlusGapInScreenPixels;
					int ysTopOfIdealScreen = dysPageTopScreen + ysTopOfTopPageScreen;
					int ysBottomOfIdealScreen = dysPageBottomScreen + ysTopOfBottomPageScreen;
					int scrollPosScreen = -AutoScrollPosition.Y;
					int clientHeightScreen = ClientRectangle.Height;
					// The amount we need to scroll by. This gets subtracted from the distance
					// we are scrolled (autoscrollposition.Y = -autoscrollposition.Y -
					// dysScrollPos), so a positive value causes the document to move up in the
					// window (thumb moves down).
					int dysScrollPosScreen = 0; // distance we need to scroll (positive = down)
					// The screen height of the rectangle we want to be visible.
					int dysIdealHeightScreen = ysBottomOfIdealScreen - ysTopOfIdealScreen;
					// The amount of space to spare...what we have to play with as we
					// decide where on the screen to try to place the rectangle we want to see.
					int dysSlackScreen = clientHeightScreen - dysIdealHeightScreen;
					// Reduce the height of the rectangle we want to make visible,if necessary, so
					// it fits on the client window. Reduce it at the 'anchor' not the 'end'.
					if (dysSlackScreen < 0)
					{
						if (!fEndBeforeAnchor)
						{
							ysTopOfIdealScreen -= dysSlackScreen;
						}
						else
							ysBottomOfIdealScreen += dysSlackScreen;
						dysIdealHeightScreen = clientHeightScreen;
						dysSlackScreen = 0;
					}
					if (rcSelPrinter.Width > clientWidthPrinter)
					{
						int delta = rcSelPrinter.Width - clientWidthPrinter;
						rcSelPrinter.Width = rcSelPrinter.Width - delta;
					}
					if (scrollPosScreen + clientHeightScreen < ysBottomOfIdealScreen)
					{
						// need to move doc up in window: dysScrollPos is negative
						dysScrollPosScreen = scrollPosScreen + clientHeightScreen - ysBottomOfIdealScreen;
					}
					else if (scrollPosScreen > ysTopOfIdealScreen)
					{
						// need to move doc down in window: dysScrollPos is positive.
						dysScrollPosScreen = scrollPosScreen - ysTopOfIdealScreen;
					}
					if (dysScrollPosScreen == 0)
					{
						// No need to move!! Unless...maybe we moved a long way, and redrawing
						// is going to expand a lazy box above our selection on the screen, and
						// it will grow so much we can't see the selection after all...
						// This ensures that everything in the client rectangle is real boxes.
						PrepareToDrawPages(0, clientHeightScreen);
						if (!vwsel.IsValid)
						{
							// At least one case where it might not be is typing in a footnote using smushing.
							// If the height of the footnote paragraph changes it gets regenerated. A new substitute
							// selection is created, but the old actual selection object isn't valid.
							// Of course, it's POSSIBLE that the selection we're trying to scroll isn't the
							// focussed root box's one, but that's the best guess I can see to make. It's right
							// for the only case so far where this has happened.
							vwsel = FocusedRootBox.Selection;
						}
						Rect rcPrimary2 = GetSelectionRectangle(vwsel, vg, out fEndBeforeAnchor);
						if (rcPrimary2.top != rcSelPrinter.Top)
							continue; // PrepareToDrawPages expanded something, try again.
						return true;
					}
					if (dysScrollPosScreen > 0)
					{
						// doc moving down. dysScrollPos as currently computed will put the rectangle
						// we want to see at the very top of the screen. That is good both for
						// case default (it's the smallest movement that works) and for a request
						// to put it at the top. Since it's at the top, no previous page can be
						// visible above it, so we will just use this value.
						// It we wanted to, say, center it, we would add half of dysSlack, then
						// make sure no previous page is showing by taking the min of that and
						// the distance to move the top of page to top of screen.
					}
					else
					{
						// doc moving up. (-dysScrollPos) is the distance to align the
						// bottom of the ideal rectangle with the bottom of the screen.
						// That is our default. If aligning to the top, we want to move more.
						if (ssoFlag == VwScrollSelOpts.kssoNearTop)
						{
							// To align the tops instead, make dysScrollPos more negative
							// by the difference between the rectangle heights.
							dysScrollPosScreen -= dysSlackScreen;
						}
						// Now we need to check that no previous page is visible. We avoid showing
						// a previous page partly because it tends to put a lot of white space
						// on the screen that may not be helpful to the user, but mainly because
						// it is possible that the previous page has not been laid out, and
						// laying it out will expand lazy boxes and mess up our prediction of
						// where the ideal rectangle will appear. We could all PrepareToDraw to
						// check whether this happens and then 'continue' to try again if
						// necessary, but we suspect it would make things jerky.
						int ysTopOfTopPageScrn = ysTopOfTopPageScreen + AutoScrollPosition.Y;
						if (ysTopOfTopPageScrn + dysScrollPosScreen > 0)
						{
							// Need to scroll more so that no previous page shows.
							// Scroll to put top of page exactly at top of screen.
							dysScrollPosScreen = -ysTopOfTopPageScrn;
						}
					}
					// OK, moving by dysScrollPos should make the selection visible
					// without expanding anything lazy above it. Do it and end the loop!
					AutoScrollPosition =
						new Point(-AutoScrollPosition.X,
						-AutoScrollPosition.Y - dysScrollPosScreen);
					return true;
				}
			}
			finally
			{
				ReleaseGraphics(vg);
			}
		}
예제 #6
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Layout a page :-)
		/// </summary>
		/// <param name="page">The page to lay out</param>
		/// <returns><c>true</c> if the remainder of this division completely fits on this page;
		/// <c>false</c> if there is additional material from this division to lay out on
		/// subsequent pages.</returns>
		/// ------------------------------------------------------------------------------------
		internal bool LayoutPage(Page page)
		{
			CheckDisposed();
			Debug.Assert(!page.IsDisposed);

			using (new SuspendDrawing(Publication))
			using (new WaitCursor(Publication))
			{
				int offsetFromTopOfDiv = page.OffsetFromTopOfDiv(this);
				int ysStartNextPage;
				int leftMargin = LeftMarginInPrinterPixels(page);

				int dysSpaceUsedOnPage;
				IVwGraphics vg = Publication.PrinterGraphics;
				MainLayoutStream.LayoutPage(vg, AvailableMainStreamColumWidthInPrinterPixels,
					page.FreeSpace.Height, ref offsetFromTopOfDiv, page.Handle,
					m_numberMainStreamColumns, out dysSpaceUsedOnPage, out ysStartNextPage);
				Publication.ReleaseGraphics(vg);

				// It's possible that the layout deleted the page (TE-7839)
				if (page.IsDisposed)
				{
					Debug.WriteLine("Page got deleted in MainLayoutStream.LayoutPage.");
					return true;
				}

				if (dysSpaceUsedOnPage == 0)
				{
					Debug.WriteLine(string.Format("Division '{0}' didn't use any space on page {1}",
						Name, page.PageNumber));
					return true;
				}

				// Layout and add column page elements in main layout stream.
				for (int iColumn = 0; iColumn < m_numberMainStreamColumns; iColumn++)
				{
					int heightThisColumn = MainLayoutStream.ColumnHeight(iColumn);
					int overlapThisColumn = MainLayoutStream.ColumnOverlapWithPrevious(iColumn);
					AddElement(page, dysSpaceUsedOnPage, iColumn + 1, m_numberMainStreamColumns, leftMargin,
						offsetFromTopOfDiv, heightThisColumn, overlapThisColumn);

					offsetFromTopOfDiv += heightThisColumn;
				}

				bool fCompletedDivision = (ysStartNextPage <= 0);
				if (!fCompletedDivision)
				{
					// We need more pages for this division; nothing more on this page
					Page nextPage = Publication.PageAfter(page);
					if (nextPage != null && Publication.Divisions[nextPage.FirstDivOnPage] == this)
					{
						// There is already another page for this division; adjust its start position.
						nextPage.AdjustOffsetFromTopOfDiv(ysStartNextPage);
					}
					else
					{
						// There are no more pages for this division; insert one.
						nextPage = InsertPage(ysStartNextPage, page);
					}
				}
				else
				{
					// Delete any subsequent pages for this same division.
					for (Page nextPage = Publication.PageAfter(page); nextPage != null; )
					{
						// If nextPage belongs to another division, we're all done.
						if (nextPage.FirstDivOnPage < Publication.Divisions.Count &&
							Publication.Divisions[nextPage.FirstDivOnPage] != this)
							break;
						Page delPage = nextPage;
						nextPage = Publication.PageAfter(nextPage);
						Publication.DeletePage(delPage);
					}
				}
				return fCompletedDivision;
			}
		}
예제 #7
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Figure out what is going to be placed on each page and where, for the given area.
		/// </summary>
		/// <param name="dypTop">offset in screen pixels to the top of the rectangle that is
		/// about to be laid out (relative to the client rectangle top)</param>
		/// <param name="dypBottom">offset in screen pixels to the bottom of the rectangle that
		/// is about to be laid out (relative to the client rectangle top)</param>
		/// <returns>A list of pages to be drawn</returns>
		/// ------------------------------------------------------------------------------------
		public List<Page> PrepareToDrawPages(int dypTop, int dypBottom)
		{
			CheckDisposed();

			if (dypBottom <= dypTop || PageHeight <= 0 || m_pages.Count == 0)
				return null;

			lock (m_pages)
			{
				int dypPageHeight = PageHeightPlusGapInScreenPixels;
				Debug.WriteLine("dyPageHeight=" + dypPageHeight);

				List<Page> pages = new List<Page>();

				// Before we start laying out the pages in detail, make sure there are real boxes
				// at least at the top of the area needing to be laid out.
				// Note that side effects of this (happening in the AdjustScrollPosition callback
				// to DivisionLayoutMgr) may change the collection of pages and/or the scroll
				// position. If that happens, the method returns true, and we need to recompute
				// which is the first page we want to lay out, and make sure that we don't have any
				// lazy boxes at that position. Any time that EnsureRealBoxAt returns true, something
				// has been converted from lazy to real, so the process is sure to terminate.
				while ((dypTop - ScrollPosition.Y) / dypPageHeight < m_pages.Count &&
					EnsureRealBoxAt(m_pages[(dypTop - ScrollPosition.Y) / dypPageHeight]))
					;

				// We need to call LayoutIfNeeded for any page that intersects the client
				// rectangle, not just the clip rectangle. This is because, in the case of 'broken'
				// pages that have been messed up by editing in the view, the Layout method of the
				// page may actually detect additional screen areas requiring redrawing.
				// On the other hand, if the clip rectangle is larger than the client rectangle,
				// we need to use those dimensions...mainly because we pass large rectangles
				// for testing purposes.
				dypTop = 0;
				dypBottom = Math.Max(dypBottom, this.ClientRectangle.Bottom);

				// The last page to be laid out will be the last page whose top is less than
				// the bottom of the rectangle being painted.
				// Note: do not calculate limit allowing for m_pages.Count, as that may increase
				// during the process of laying out pages.
				int limPage = (dypBottom - ScrollPosition.Y + dypPageHeight - 1) / dypPageHeight;
				Debug.WriteLine(string.Format("dypBottom={0}, limPage={1}, startPage={2}, ScrollPos.Y={3}, pages.Count={4}",
					dypBottom, limPage, (dypTop - ScrollPosition.Y) / (dypPageHeight), ScrollPosition.Y, m_pages.Count));

				// The first page to be laid out will be the first page whose bottom is greater than
				// or equal to the top of the rectangle being painted.
				for (int iPage = (dypTop - ScrollPosition.Y) / (dypPageHeight);
					iPage < limPage && iPage < m_pages.Count;
					iPage++)
				{
					// We need to store the page in a temp variable because it is, theoretically,
					// possible that something else like ScrollSelectionIntoView() might get
					// called during the layout (probably another problem) and set
					// m_pageBeingLaidOut to null before we add it to the page list.
					Page page = m_pageBeingLaidOut = m_pages[iPage];
					Debug.WriteLine(string.Format("Laying out page {0} (iPage={1})", m_pageBeingLaidOut.PageNumber, iPage));
					page.LayOutIfNeeded();
//					page.ReadyForDrawing = true;
					pages.Add(page);
				}
				m_pageBeingLaidOut = null;
				Debug.WriteLine("Done preparing pages to draw");

				return pages;
			}
		}
예제 #8
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Delete the given page. This is broken out as a method in case
		/// we decide to change to a linked list or something more complex.
		/// </summary>
		/// <param name="page"></param>
		/// ------------------------------------------------------------------------------------
		public void DeletePage(Page page)
		{
			CheckDisposed();

			lock (m_pages)
			{
				int pageIndex = IndexOfPage(page);
				m_pages.Remove(page);
				AdjustPagesAfter(pageIndex - 1);
				AdjustAutoScrollRange();
				// TODO: If autoscroll position changes, need to invalidate
				page.Dispose();
			}
		}
예제 #9
0
		public void Pub_ThreeDivisions_EachDivStartsNewPage()
		{
			DummyDivision secondDiv = new DummyDivision(
				new DummyPrintConfigurer(Cache, m_subStream), 2);
			DummyDivision thirdDiv = new DummyDivision(
				new DummyPrintConfigurer(Cache, m_subStream), 1);
			thirdDiv.StartAt = secondDiv.StartAt = m_firstDivision.StartAt = DivisionStartOption.NewPage;
			m_pub.AddDivision(secondDiv);
			m_pub.AddDivision(thirdDiv);

			m_pub.PageHeight = 72000 * 11; // 11 inches
			m_pub.PageWidth = 72000 * 8; // 8 inches
			thirdDiv.TopMargin = m_firstDivision.TopMargin = 36000; // Half inch
			thirdDiv.BottomMargin = m_firstDivision.BottomMargin = 18000; // Quarter inch
			thirdDiv.InsideMargin = m_firstDivision.InsideMargin = 9000; // 1/8 inch
			thirdDiv.OutsideMargin = m_firstDivision.OutsideMargin = 4500; // 1/16 inch
			m_pub.CreatePages();
			Assert.AreEqual(4, m_pub.Pages.Count);
			Page firstPage = m_pub.Pages[0];
			Assert.AreEqual(m_firstDivision, m_pub.Divisions[firstPage.FirstDivOnPage]);
			Page origPage2 = m_pub.PageAfter(firstPage);
			Assert.AreEqual(m_pub.Pages[1], origPage2);
			Assert.AreEqual(secondDiv, m_pub.Divisions[origPage2.FirstDivOnPage]);
			Assert.AreEqual(0, m_pub.IndexOfPage(firstPage));
			Page lastPage = m_pub.Pages[3];
			Assert.AreEqual(thirdDiv, m_pub.Divisions[lastPage.FirstDivOnPage]);
			Assert.AreEqual(3, m_pub.IndexOfPage(lastPage),
				"IndexOfPage returned wrong value for last page");
			Page extraPage = new Page(m_pub, 1, 0, 2,
				m_firstDivision.TopMarginInPrinterPixels, m_firstDivision.BottomMarginInPrinterPixels);
			m_pub.InsertPageAfter(firstPage, extraPage);
			Assert.AreEqual(m_pub.Pages[1], extraPage);
			Assert.AreEqual(m_pub.Pages[2], origPage2);
			Assert.AreEqual(m_pub.Pages[4], lastPage);
			Assert.AreEqual(firstPage, m_pub.FindPage(firstPage.Handle));
			Assert.AreEqual(extraPage, m_pub.FindPage(extraPage.Handle));
			Assert.AreEqual(origPage2, m_pub.FindPage(origPage2.Handle));
			Assert.AreEqual(lastPage, m_pub.FindPage(lastPage.Handle));
			m_pub.DeletePage(extraPage);
			Assert.AreEqual(m_pub.Pages[1], origPage2);
			Assert.IsNull(m_pub.PageAfter(lastPage));

			m_pub.PrepareToDrawPages(0, 99999);
			Assert.AreEqual(7, m_pub.Pages.Count);
			Assert.AreEqual(2, firstPage.PageElements.Count);
			Assert.AreEqual(3, origPage2.PageElements.Count, "Should have one element per column, plus one for footnotes.");
			Assert.AreEqual(2, lastPage.PageElements.Count);

			Assert.AreEqual(m_firstDivision.MainRootBox.Height, thirdDiv.MainRootBox.Height);
			Assert.AreNotEqual(m_firstDivision.MainRootBox.Height, secondDiv.MainRootBox.Height);
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Checks that the page elements don't overlap.
		/// </summary>
		/// <param name="page">The page.</param>
		/// ------------------------------------------------------------------------------------
		private static void CheckThatPageElementsDontOverlap(Page page)
		{
			for (int i = 0; i < page.PageElements.Count; i++)
			{
				PageElement pe = page.PageElements[i];
				for (int j = i + 1; j < page.PageElements.Count; j++)
				{
					PageElement otherPe = page.PageElements[j];
					Assert.IsFalse(pe.LocationOnPage.IntersectsWith(otherPe.LocationOnPage));
				}
			}
		}
예제 #11
0
		public void PublicationPageCollection()
		{
			m_pub.PageHeight = 144000; // 2 inches
			m_pub.PageWidth = 216000; // 3 inches
			m_firstDivision.TopMargin = 36000; // Half inch
			m_firstDivision.BottomMargin = 18000; // Quarter inch
			m_firstDivision.InsideMargin = 9000; // 1/8 inch
			m_firstDivision.OutsideMargin = 4500; // 1/16 inch
			m_pub.CreatePages();
			Assert.IsTrue(m_pub.Pages.Count >= 1);
			Page firstPage = m_pub.Pages[0];
			Page origPage2 = m_pub.PageAfter(firstPage);
			Assert.AreEqual(0, m_pub.IndexOfPage(firstPage));
			Page lastPage = m_pub.Pages[m_pub.Pages.Count - 1];
			Assert.AreEqual(m_pub.Pages.Count - 1, m_pub.IndexOfPage(lastPage),
				"IndexOfPage returned wrong value for last page");
			Assert.AreEqual(m_pub.Pages[1], origPage2);
			Page extraPage = new Page(m_pub, 0, 0, 2,
				m_firstDivision.TopMarginInPrinterPixels, m_firstDivision.BottomMarginInPrinterPixels);
			m_pub.InsertPageAfter(firstPage, extraPage);
			Assert.AreEqual(m_pub.Pages[1], extraPage);
			Assert.AreEqual(m_pub.Pages[2], origPage2);
			Assert.AreEqual(firstPage, m_pub.FindPage(firstPage.Handle));
			Assert.AreEqual(extraPage, m_pub.FindPage(extraPage.Handle));
			Assert.AreEqual(origPage2, m_pub.FindPage(origPage2.Handle));
			Assert.AreEqual(lastPage, m_pub.FindPage(lastPage.Handle));
			m_pub.DeletePage(extraPage);
			Assert.AreEqual(m_pub.Pages[1], origPage2);
			Assert.IsNull(m_pub.PageAfter(lastPage));
		}
예제 #12
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Add the page element.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <param name="dysSpaceUsedOnPage">The amount of vertical space taken up by this
		/// element on this page.</param>
		/// <param name="currentColumn">The 1-based index of the current column.</param>
		/// <param name="numberColumns">The total number columns for the stream.</param>
		/// <param name="leftMargin">The left margin.</param>
		/// <param name="offsetFromTopOfDiv">The offset from top of division.</param>
		/// <param name="columnHeight">The height of the column.</param>
		/// ------------------------------------------------------------------------------------
		internal void CallAddElement(Page page, int dysSpaceUsedOnPage,
			int currentColumn, int numberColumns, int leftMargin,
			int offsetFromTopOfDiv, int columnHeight)
		{
			base.AddElement(page, dysSpaceUsedOnPage, currentColumn, numberColumns, leftMargin,
				offsetFromTopOfDiv, columnHeight, 0);
		}
예제 #13
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Add page header and footer elements to the given page.
		/// </summary>
		/// <param name="page">The page to add the header to</param>
		/// ------------------------------------------------------------------------------------
		internal void AddHeaderAndFooter(Page page)
		{
			int leftMargin = LeftMarginInPrinterPixels(page);
			AddHeaderAndFooter(page, leftMargin);
		}
예제 #14
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Find the page preceding the given page. This is broken out as a method in case
		/// we decide to change to a linked list or something more complex.
		/// </summary>
		/// <param name="page"></param>
		/// <returns></returns>
		/// ------------------------------------------------------------------------------------
		public Page PageBefore(Page page)
		{
			CheckDisposed();

			int iPage = IndexOfPage(page) - 1;
			if (iPage < 0)
				return null;
			return m_pages[iPage];
		}
예제 #15
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Ensure that the data corresponding to the location of the given page consists of
		/// real boxes, not lazy ones.
		/// </summary>
		/// <param name="page"></param>
		/// <returns>true if it had to do anything...the caller should recheck the scroll
		/// position and which pages need drawing, and call again.</returns>
		/// ------------------------------------------------------------------------------------
		public bool EnsureRealBoxAt(Page page)
		{
			CheckDisposed();

			bool result = false;
			DivisionLayoutMgr div = m_divisions[page.FirstDivOnPage];
			// ENHANCE (TE-5866): Do this for all divisions on the page.

			IVwGraphics vg = PrinterGraphics;
			try
			{
				int offset = page.OffsetFromTopOfDiv(div);
				Rect rcPage = new Rect(0, offset, PageWidthInPrinterPixels,
					offset + PageHeightInPrinterPixels);
				((IVwGraphicsWin32)vg).SetClipRect(ref rcPage);
				Rect rcTrans = new Rect(0, 0, (int)DpiXPrinter, (int)DpiYPrinter);
				// Make sure we have real data in this section of the root.
				if (div.MainRootBox != null)
				{
					result = div.MainRootBox.PrepareToDraw(vg, rcTrans, rcTrans) !=
						VwPrepDrawResult.kxpdrNormal;
				}
			}
			finally
			{
				ReleaseGraphics(vg);
			}
			return result;
		}
예제 #16
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Insert a page before the given page. This is broken out as a method in case
		/// we decide to change to a linked list or something more complex.
		/// </summary>
		/// <param name="page"></param>
		/// <param name="newPage"></param>
		/// ------------------------------------------------------------------------------------
		public void InsertPageBefore(Page page, Page newPage)
		{
			CheckDisposed();

			lock (m_pages)
			{
				int index = IndexOfPage(page);
				m_pages.Insert(index, newPage);
				AdjustPagesAfter(index - 1);
				AdjustAutoScrollRange();
			}
		}
예제 #17
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Inserts a new page after the given one.
		/// </summary>
		/// <param name="indexOfDiv">The index of this division in the publication</param>
		/// <param name="ypOffsetFromTopOfDiv">The offset from top of this division to the
		/// start of the page to insert.</param>
		/// <param name="pageToInsertAfter">The page to insert after.</param>
		/// <returns>The newly inserted page</returns>
		/// ------------------------------------------------------------------------------------
		internal Page InsertPage(int indexOfDiv, int ypOffsetFromTopOfDiv, Page pageToInsertAfter)
		{
			DivisionLayoutMgr div = Divisions[indexOfDiv];
			Page newPage = CreatePage(this, indexOfDiv, ypOffsetFromTopOfDiv,
				pageToInsertAfter.PageNumber + 1, div.TopMarginInPrinterPixels,
				div.BottomMarginInPrinterPixels);
			InsertPageAfter(pageToInsertAfter, newPage);
			return newPage;
		}
예제 #18
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Return coordinate transformation suitable for screen drawing in the specified
		/// element of the specified page.
		/// </summary>
		/// <param name="page"></param>
		/// <param name="pe"></param>
		/// <param name="rcSrcRoot"></param>
		/// <param name="rcDstRoot"></param>
		/// ------------------------------------------------------------------------------------
		protected void GetCoordRectsForElt(Page page, PageElement pe, out Rect rcSrcRoot,
			out Rect rcDstRoot)
		{
			// The origin of this rectangle is the offset from the origin of this rootbox's
			// data to the origin of this element (in printer pixels). Size is DPI.
			Rectangle rectSrc = new Rectangle(0, pe.OffsetToTopPageBoundary - pe.OverlapWithPreviousElement,
				(int)(DpiXPrinter), (int)(DpiYPrinter));
			rcSrcRoot = new Rect(rectSrc.Left, rectSrc.Top, rectSrc.Right, rectSrc.Bottom);

			Rectangle rectElement = pe.PositionInLayoutForScreen(IndexOfPage(page), this,
				DpiXScreen, DpiYScreen);
			// The origin of this rectangle is the offset from the origin of this element
			// to the origin of the clip rectangle (the part of the rc that
			// actually pertains to this element) (in screen pixels)
			Rectangle rectDst = new Rectangle(rectElement.Left,
				rectElement.Top, (int)(DpiXScreen * Zoom), (int)(DpiYScreen * Zoom));
			rcDstRoot = new Rect(rectDst.Left, rectDst.Top, rectDst.Right, rectDst.Bottom);
		}
예제 #19
0
		/// -------------------------------------------------------------------------------------
		/// <summary>
		/// Inserts additonal pages if needed at dydPosition to approximately match the new
		/// estimated height when a lazy box has been expanded.
		/// </summary>
		/// <param name="changedSizePage">The last page whose top doesn't move (i.e., the one the
		/// lazy box is actually on). We may need to insert pages just after this.</param>
		/// <param name="strm">The IVwLayoutStream interface of the rootbox that is the main
		/// stream on at least some of the pages of this publication (i.e., this publication
		/// should be the IVwRootsite of the given rootbox).</param>
		/// <param name="dydSize">The amount the rootbox grew, in printer pixels. This is
		/// guaranteed to be positive.</param>
		/// <param name="dydPosition">The top of the lazy box which was (partially) expanded,
		/// split, etc (in printer pixels). Or the position of the top of the real box that got
		/// relazified.
		/// </param>
		/// <returns>true if there are not enough pages for the AutoScrollPosition to increase as
		/// much as required.</returns>
		/// -------------------------------------------------------------------------------------
		private bool InsertAdditionalPages(Page changedSizePage, IVwLayoutStream strm,
			int dydSize, int dydPosition)
		{
			Debug.Assert(changedSizePage != null);
			Debug.Assert(dydSize > 0);

			Page nextPage = PageAfter(changedSizePage);
			int heightOfChangedPage; // Current height, to next page or estimated end of doc.
			int iDiv = DivisionIndexForMainStream(strm);
			DivisionLayoutMgr divMgr = Divisions[iDiv];

			if (nextPage == null)
			{
				heightOfChangedPage = dydSize;
				// An empty page may have nothing from the main stream - can happen when project is
				// empty or filter excludes all content
				PageElement pe = changedSizePage.GetFirstElementForStream(strm);
				if (pe != null)
					heightOfChangedPage -= pe.OffsetToTopPageBoundary;
			}
			else
			{
				heightOfChangedPage = nextPage.OffsetFromTopOfDiv(divMgr) -
					changedSizePage.OffsetFromTopOfDiv(divMgr);
			}

			int desiredPageHeight = divMgr.AvailablePageHeightInPrinterPixels;
			// This computes the number of pages to add, if any, so that
			// if the tops of the pages are more than a page and a half apart we
			// insert enough pages so no page is more than an ideal page and a half long.
			// Subtracting half the desired page height accounts both for rounding and
			// the fact that one page (rather than zero) is the desired page height.
			int numberOfPagesToAdd = (heightOfChangedPage - desiredPageHeight / 2) /
				desiredPageHeight;
			// Pathologically, it might be possible for that calculation to produce
			// a negative number, if this page has shrunk to less than a half page from
			// previous lazy box expansions.
			if (numberOfPagesToAdd < 0)
				numberOfPagesToAdd = 0;
			Page pageToInsertAfter = changedSizePage;
			for (int i = 0; i < numberOfPagesToAdd; i++)
			{
				// Insert a new page.
				pageToInsertAfter = InsertPage(iDiv,
					pageToInsertAfter.OffsetFromTopOfDiv(divMgr) + desiredPageHeight,
					pageToInsertAfter);
			}
			// If we're increasing the autoscroll position, do it AFTER we possibly adjust
			// the autoscroll range, otherwise, the increased value might be greater than
			// the old range and get truncated.
			// Remember: Microsoft's idea of how to set AutoScrollPosition is brain-dead. We read
			// it as negative and have to set it as positive.
			int dydPosScreen = (int)(dydPosition * DpiYScreen / DpiYPrinter);
			if (-AutoScrollPosition.Y > dydPosScreen)
			{
				int dydDesiredAutoScrollY = (int)(AutoScrollPosition.Y - (dydSize * DpiYScreen /
					DpiYPrinter)); // larger negative
				AutoScrollPosition = new Point(
					-AutoScrollPosition.X, -dydDesiredAutoScrollY);
				// Something messy happened if we can't achieve that position (presumably
				// it is out of range, we didn't add enough pages).
				return (AutoScrollPosition.Y != dydDesiredAutoScrollY);
			}
			return false; // We get here only if we didn't have to adjust scroll position at all.
		}
예제 #20
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// If it's an odd page, return the inside margin; even page, return the outside margin.
		/// If this is a right-bound publication, then do the opposite.
		/// </summary>
		/// <param name="page">The <see cref="Page"/> for which the margin is needed. Needed so
		/// we know whether to use the inside or outside margin.</param>
		/// <returns>If it's an odd page, returns the inside margin; if an even page, returns
		/// the outside margin. If this is a right-bound publication, then does the opposite.
		/// </returns>
		/// ------------------------------------------------------------------------------------
		public int LeftMarginInPrinterPixels(Page page)
		{
			CheckDisposed();
			Debug.Assert(!page.IsDisposed);

			return LeftMarginInPrinterPixels(page.PageNumber);
		}
예제 #21
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Invalidate the specified rectangle, which is in printer coordinates relative
		/// to the top left of the page.
		/// </summary>
		/// <param name="page"></param>
		/// <param name="rect"></param>
		/// ------------------------------------------------------------------------------------
		internal void InvalidatePrintRect(Page page, Rectangle rect)
		{
			CheckDisposed();

			int indexOfPage = this.IndexOfPage(page);
			int topOfPage = indexOfPage * PageHeightPlusGapInScreenPixels;
			// Relative to page, but in screen coordinates.
			Rectangle rectOnPageScreen = Rectangle.FromLTRB(
				this.ConvertPrintDistanceToTargetX(rect.Left, DpiXScreen),
				this.ConvertPrintDistanceToTargetY(rect.Top, DpiYScreen),
				this.ConvertPrintDistanceToTargetX(rect.Right, DpiXScreen),
				this.ConvertPrintDistanceToTargetY(rect.Bottom, DpiYScreen));
			Rectangle rectToInvert = rectOnPageScreen;
			rectToInvert.Offset(ScrollPosition.X, ScrollPosition.Y + topOfPage);
			rectToInvert.Inflate(0, 2); // for out-of-bounds diacritics and descenders, etc.
			this.Invalidate(rectToInvert, true);
		}
예제 #22
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Inserts a new page after the given one.
		/// </summary>
		/// <param name="ypOffsetFromTopOfDiv">The offset from top of this division to the
		/// start of the page to insert.</param>
		/// <param name="pageToInsertAfter">The page to insert after.</param>
		/// <returns>The newly inserted page</returns>
		/// ------------------------------------------------------------------------------------
		private Page InsertPage(int ypOffsetFromTopOfDiv, Page pageToInsertAfter)
		{
			Debug.Assert(!pageToInsertAfter.IsDisposed);
			return Publication.InsertPage(Publication.IndexOfDiv(this), ypOffsetFromTopOfDiv,
				pageToInsertAfter);
		}
예제 #23
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Find the element which contains the specified point.
		/// This should be a point that is actually visible on the screen, so that lazy
		/// stuff doesn't have to be expanded.
		/// If there is no element at the specified point we'll look for the first page
		/// element with the same Y position. If there is none with the same Y position
		/// we return <c>null</c>.
		/// </summary>
		/// <param name="pt">Point at display resolution relative to top left of client area</param>
		/// <param name="scrollPos">AutoScrollPosition (an argument for testing purposes).</param>
		/// <param name="ptLayout">Point at layout resolution relative to top left of
		/// document (for the element's stream).</param>
		/// <param name="page">The page.</param>
		/// <returns>Element at position <paramref name="pt"/> (or with the same Y-position),
		/// or <c>null</c> if there is no element at position <paramref name="pt"/>.</returns>
		/// <remarks>ENHANCE: find closest element instead of getting first element with same
		/// Y position if there is no element at specified position.</remarks>
		/// ------------------------------------------------------------------------------------
		public PageElement ElementFromPoint(Point pt, Point scrollPos, out Point ptLayout,
			out Page page)
		{
			CheckDisposed();

			ptLayout = pt; // arbitrary, but compiler insists.
			page = null;
			if (Pages == null || Pages.Count == 0)
				return null;

			Point ptDoc = pt;
			ptDoc.Offset(-scrollPos.X, -scrollPos.Y); // relative to whole seq of pages
			int ipage = ptDoc.Y / PageHeightPlusGapInScreenPixels;

			if (ipage < 0 || ipage >= Pages.Count)
				return null;

			Point ptPageScrn = ptDoc; // relative to page in screen pixels
			ptPageScrn.Offset(0, -ipage * PageHeightPlusGapInScreenPixels);
			Point ptPage = new Point(ConvertScreenDistanceToPrinterX(ptPageScrn.X, DpiXScreen),
				ConvertScreenDistanceToPrinterY(ptPageScrn.Y, DpiYScreen));
			page = Pages[ipage] as Page;
			if (page.NeedsLayout)
				return null;
			foreach (PageElement pe in page.PageElements)
			{
				if (pe.LocationOnPage.Contains(ptPage))
				{
					ptLayout = ptPage;
					ptLayout.Offset(-pe.LocationOnPage.Left,
						pe.OffsetToTopPageBoundary - pe.LocationOnPage.Top);
					return pe;
				}
			}

			// No page element at the given point. Is there one to the right or left
			// of it?
			PageElement bestChoice = null;
			foreach (PageElement pe in page.PageElements)
			{
				if (pe.LocationOnPage.Top <= ptPage.Y && ptPage.Y <= pe.Bottom)
				{
					if (bestChoice == null ||
						DistanceXFromRect(bestChoice.LocationOnPage, ptPage) >
						DistanceXFromRect(pe.LocationOnPage, ptPage))
					{
						bestChoice = pe;
					}
				}
			}

			if (bestChoice != null)
			{
				ptLayout = ptPage;
				ptLayout.Offset(-bestChoice.LocationOnPage.Left,
					bestChoice.OffsetToTopPageBoundary - bestChoice.LocationOnPage.Top);
			}
			return bestChoice;
		}
예제 #24
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Add page header and footer elements to the given page.
		/// </summary>
		/// <param name="page">The page to add the header to</param>
		/// ------------------------------------------------------------------------------------
		internal void AddHeaderAndFooter(Page page)
		{
			Debug.Assert(!page.IsDisposed);

			int leftMargin = LeftMarginInPrinterPixels(page);
			AddHeaderAndFooter(page, leftMargin);
		}
예제 #25
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Find index of the given page. This is broken out as a method in case
		/// we decide to change to a linked list or something more complex.
		/// </summary>
		/// <param name="page"></param>
		/// <returns></returns>
		/// ------------------------------------------------------------------------------------
		public int IndexOfPage(Page page)
		{
			CheckDisposed();

			return m_pages.IndexOf(page);
		}
예제 #26
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// If it's an odd page, return the inside margin; even page, return the outside margin.
		/// If this is a right-bound publication, then do the opposite.
		/// </summary>
		/// <param name="page">The <see cref="Page"/> for which the margin is needed. Needed so
		/// we know whether to use the inside or outside margin.</param>
		/// <returns>If it's an odd page, returns the inside margin; if an even page, returns
		/// the outside margin. If this is a right-bound publication, then does the opposite.
		/// </returns>
		/// ------------------------------------------------------------------------------------
		public int LeftMarginInPrinterPixels(Page page)
		{
			CheckDisposed();

			return LeftMarginInPrinterPixels(page.PageNumber);
		}
예제 #27
-12
//		/// ------------------------------------------------------------------------------------
//		/// <summary>
//		/// Determine the gap between the columns.
//		/// </summary>
//		/// <param name="numberColumns">The total number of columns.</param>
//		/// <returns>
//		/// If the element spans the whole width of the page, the column gap is 0.
//		/// Otherwise, it is ColumnGapWidthInPrinterPixels;
//		/// </returns>
//		/// ------------------------------------------------------------------------------------
//		private int ColumnGap(int numberColumns)
//		{
//			return (numberColumns > 1) ? ColumnGapWidthInPrinterPixels : 0;
//		}

		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Adds or adjusts the page element. Note that this is used ONLY for dependent objects,
		/// it arranges them from the bottom up. These elements don't overlap, so no overlap is
		/// passed.
		/// </summary>
		/// <param name="page">The page.</param>
		/// <param name="ysTopOfPrevElement">The top of the previous element.</param>
		/// <param name="ysStreamHeight">Height of the stream.</param>
		/// <param name="stream">The stream.</param>
		/// <param name="pagePosition">The page position.</param>
		/// <returns></returns>
		/// ------------------------------------------------------------------------------------
		private int AddOrAdjustPageElement(Page page, int ysTopOfPrevElement, int ysStreamHeight,
			IVwLayoutStream stream, int pagePosition)
		{
			Debug.Assert(!page.IsDisposed);

			if (ysStreamHeight <= 0)
				return ysTopOfPrevElement;

			int ysTopOfThisElement = ysTopOfPrevElement - ysStreamHeight;
			Rectangle rectLocationOnPage = new Rectangle(LeftMarginInPrinterPixels(page),
				ysTopOfThisElement,
				AvailablePageWidthInPrinterPixels,
				ysStreamHeight);

			PageElement element = page.GetFirstElementForStream(stream);
			if (element == null)
			{
				// Create page element
				page.AddPageElement(this, stream, false, rectLocationOnPage,
					pagePosition, false, 1, 1, 0,
					ysStreamHeight, 0, MainStreamIsRightToLeft, false);
			}
			else
			{
				// Increase size of page element
				if (element.LocationOnPage.Height != ysStreamHeight)
				{
					// Increase size of/move location
					page.AdjustPageElement(element, rectLocationOnPage, false);
				}
			}
			return ysTopOfThisElement;
		}