public void CommonContainerTests() { var styles = new AssembledStyles(); var columnWidths = new FixedColumnWidths(new[] { 10 }); var root1 = new RootBox(styles); var root2 = new RootBox(styles); VerifyCC(root1, root1, root1, root1, root1); VerifyCC(root2, root2, root2, root2, root2); var row1 = new RowBox(styles, columnWidths, false); var div1 = new DivBox(styles); root2.AddBox(row1); root1.AddBox(div1); VerifyCC(row1, row1, row1, row1, row1); VerifyCC(div1, div1, div1, div1, div1); VerifyCC(root1, div1, root1, root1, div1); VerifyCC(root2, row1, root2, root2, row1); var row2 = new RowBox(styles, columnWidths, false); var div2 = new DivBox(styles); root2.AddBox(row2); root1.AddBox(div2); VerifyCC(row1, row2, root2, row1, row2); VerifyCC(div1, div2, root1, div1, div2); var row3 = new RowBox(styles, columnWidths, false); var div3 = new DivBox(styles); row1.AddBox(row3); div1.AddBox(div3); VerifyCC(row1, row3, row1, row1, row3); VerifyCC(row2, row3, root2, row2, row1); VerifyCC(div1, div3, div1, div1, div3); VerifyCC(div2, div3, root1, div2, div1); var row4 = new RowBox(styles, columnWidths, false); var div4 = new DivBox(styles); row2.AddBox(row4); div2.AddBox(div4); VerifyCC(row3, row4, root2, row1, row2); VerifyCC(row1, row4, root2, row1, row2); VerifyCC(div3, div4, root1, div1, div2); VerifyCC(div1, div4, root1, div1, div2); }
public void NextAndPrevInSelectionSeq() { var styles = new AssembledStyles(); var root = new RootBox(styles); Assert.That(root.NextInSelectionSequence(true), Is.Null); Assert.That(root.PreviousInSelectionSequence, Is.Null); var block = new BlockBox(styles, Color.Red, 6000, 6000); root.AddBox(block); Assert.That(root.NextInSelectionSequence(true), Is.EqualTo(block)); Assert.That(block.PreviousInSelectionSequence, Is.EqualTo(root)); var div = new DivBox(styles); root.AddBox(div); Assert.That(block.NextInSelectionSequence(true), Is.EqualTo(div)); Assert.That(div.PreviousInSelectionSequence, Is.EqualTo(block)); var divChild = new DivBox(styles); div.AddBox(divChild); var block2 = new BlockBox(styles, Color.Red, 6000, 6000); divChild.AddBox(block2); var block3 = new BlockBox(styles, Color.Red, 6000, 6000); divChild.AddBox(block3); var block4 = new BlockBox(styles, Color.Red, 6000, 6000); div.AddBox(block4); // up and forward Assert.That(block3.NextInSelectionSequence(true), Is.EqualTo(block4)); Assert.That(block4.PreviousInSelectionSequence, Is.EqualTo(block3)); // Can go back from a box to a previous empty group var emptyDiv = new DivBox(styles); root.AddBox(emptyDiv); var block5 = new BlockBox(styles, Color.Red, 6000, 6000); root.AddBox(block5); Assert.That(emptyDiv.NextInSelectionSequence(true), Is.EqualTo(block5)); Assert.That(block5.PreviousInSelectionSequence, Is.EqualTo(emptyDiv)); Assert.That(div.NextInSelectionSequence(true), Is.EqualTo(divChild)); Assert.That(div.NextInSelectionSequence(false), Is.EqualTo(emptyDiv)); }
public void NestedDivsLayout() { var styles = new AssembledStyles(); BlockBox box1 = new BlockBox(styles, Color.Red, 72000, 36000); BlockBox box2 = new BlockBox(styles, Color.Blue, 108000, 18000); BlockBox box3 = new BlockBox(styles, Color.Orange, 72000, 18000); BlockBox box4 = new BlockBox(styles, Color.Orange, 72000, 18000); var div1 = new DivBox(styles); var div2 = new DivBox(styles); div1.AddBox(box1); div1.AddBox(box2); div2.AddBox(box3); div2.AddBox(box4); RootBox root = new RootBox(styles); root.AddBox(div1); root.AddBox(div2); LayoutInfo layoutArgs = MakeLayoutInfo(); root.Layout(layoutArgs); Assert.That(box1.Height, Is.EqualTo(48)); Assert.That(box2.Height, Is.EqualTo(24)); Assert.That(root.Height, Is.EqualTo(48 + 24 + 24 + 24)); Assert.That(box1.Left, Is.EqualTo(0)); Assert.That(box2.Left, Is.EqualTo(0)); Assert.That(box1.Top, Is.EqualTo(0)); Assert.That(box2.Top, Is.EqualTo(48)); Assert.That(div2.Top, Is.EqualTo(48 + 24)); Assert.That(box4.Top, Is.EqualTo(24)); Assert.That(box1.Width, Is.EqualTo(96)); Assert.That(box2.Width, Is.EqualTo(144)); Assert.That(root.Width, Is.EqualTo(144)); // Now try changing the size of a block. MockSite site = new MockSite(); root.Site = site; PaintTransform ptrans = new PaintTransform(2, 4, 96, 96, 0, 10, 120, 128); site.m_transform = ptrans; site.m_vwGraphics = m_gm.VwGraphics; box2.UpdateSize(144000, 36000); Assert.That(box2.Width, Is.EqualTo(96*2)); Assert.That(box2.Height, Is.EqualTo(48)); Assert.That(div1.Height, Is.EqualTo(96)); // two children now both 48 high. Assert.That(root.Height, Is.EqualTo(48 +48 + 24 + 24)); // new heights of 4 children. Assert.That(root.Width, Is.EqualTo(96*2)); // Since it got both wider and higher, we should invalidate at least the whole current size. var bigInvalidate = root.InvalidateRect; Assert.That(site.RectsInvalidatedInRoot, Has.Member(bigInvalidate)); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 36000); Assert.That(root.Height, Is.EqualTo(48 + 48 + 24 + 24)); // unchanged this time Assert.That(root.Width, Is.EqualTo(144)); // narrower box2 still determines it // Got narrower, at least the whole old invalidate rectangle should be invalidated. Assert.That(site.RectsInvalidatedInRoot, Has.Member(bigInvalidate)); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 18000); Assert.That(root.Height, Is.EqualTo(48 + 24 + 24 + 24)); // new smaller value Assert.That(root.Width, Is.EqualTo(144)); // unchanged this time // It got shorter. We want an optimized invalidate rectangle that does not // include the top box. But it must include the space at the bottom that the root box used to occupy. // There are other possible implementations, but currently, we expect the old rectangle of box2 // to be invalidated (its in the fixmap so its own Relayout does this); // the shrinkage area at the bottom of div2; // and the area computed because div2 moved. VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48, 144, 48); // old box2 VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 24); // shrinkage of div1 // This is from the new top of div2 to its old bottom (old bottom was 48 + 48 + 24 + 24) VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 48 + 24); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 72000); Assert.That(root.Height, Is.EqualTo(48 + 96 + 24 + 24)); // new larger value Assert.That(root.Width, Is.EqualTo(144)); // unchanged this time // It got longer. We want an optimized invalidate rectangle that does not // include the top box. But it must include the space at the bottom where the root box grew. // There are other possible implementations, but currently, we expect the old rectangle of box2 // to be invalidated (it returns true from Relayout); // the growth area at the bottom of div2; // and the area computed because div2 moved. VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48, 144, 96); // new box2 VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 96 - 24); // new part of div1 occupied by box2 // This is from the old top of div2 to its new bottom (48 + 96 + 24 + 24) VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 96 + 24); }
public void DivClippedPaint() { var styles = new AssembledStyles(); var box1 = new FgBlockBox(styles, Color.Red, 72000, 36000); var box2 = new FgBlockBox(styles, Color.Blue, 108000, 18000); var box3 = new FgBlockBox(styles, Color.Orange, 72000, 18000); var box4 = new FgBlockBox(styles, Color.Orange, 72000, 18000); var div1 = new DivBox(styles); div1.AddBox(box1); div1.AddBox(box2); div1.AddBox(box3); div1.AddBox(box4); RootBox root = new RootBox(styles); root.AddBox(div1); LayoutInfo layoutArgs = MakeLayoutInfo(); root.Layout(layoutArgs); var rect1 = new Rectangle(0, 0, 96, 48); var rect2 = new Rectangle(0, 0, 144, 24); rect2.Offset(0, rect1.Bottom); var rect3 = new Rectangle(0, 0, 96, 24); rect3.Offset(0, rect2.Bottom); var rect4 = new Rectangle(0, 0, 96, 24); rect4.Offset(0, rect3.Bottom); var paintRects = new[] { rect1, rect2, rect3, rect4 }; VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 2000), 0, 0, paintRects); // Clipping off the top part, but not the whole, of a box does not prevent drawing it. VerifyPaint(root, new Rectangle(-1000, 10, 2000, -10 + rect4.Bottom - 10), 0, 0, paintRects); // Even clipping all but one pixel does not prevent drawing. VerifyPaint(root, new Rectangle(-1000, 47, 2000, -47 + rect3.Bottom + 1), 0, 0, paintRects); // However if we clip a bit more we should draw less var middleTwo = new[] {rect2, rect3}; VerifyPaint(root, new Rectangle(-1000, 48, 2000, -48 + rect3.Bottom - 2), 0, 0, middleTwo); // If the clip covers just a bit of the first box we paint just that. var firstOne = new[] {rect1}; VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 1000 + 10), 0, 0, firstOne); // If the clip covers just a bit of the last box we paint just that. var lastOne = new[] { rect4 }; VerifyPaint(root, new Rectangle(-1000, rect4.Bottom - 2, 2000, 1000), 0, 0, lastOne); // If the clip is entirely above the pile we draw nothing. VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 990), 0, 0, null); // Likewise if entirely below. VerifyPaint(root, new Rectangle(-1000, rect4.Bottom + 10, 2000, 10), 0, 0, null); // Now try with simulated scrolling. Use a normal clip rectangle, but pretend the first two // and a bit boxes are scrolled off. var offset = rect2.Bottom + 10; var rect3Offset = rect3; rect3Offset.Offset(0, -offset); var rect4Offset = rect4; rect4Offset.Offset(0, -offset); var lastTwoOffset = new[] {rect3Offset, rect4Offset}; VerifyPaint(root, new Rectangle(-1000, 0, 2000, 200), 0, offset, lastTwoOffset); }
public void ComplexRangeDrawing() { var string1 = "This is the day that the Lord has made."; var string2 = "We will rejoice and be glad in it."; var string3 = "Love the Lord your God with all your heart."; var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 }; var factory = new FakeRendererFactory(); factory.SetRenderer(34, engine); var runStyle = new AssembledStyles().WithWs(34); var lineHeightMp = 20000; var style = new AssembledStyles().WithLineHeight(lineHeightMp); var root = new RootBox(style); var para1 = MakePara(style, runStyle, string1); root.AddBox(para1); var div = new DivBox(style); root.AddBox(div); var para2 = MakePara(style, runStyle, string2); div.AddBox(para2); var para3 = MakePara(style, runStyle, string3); div.AddBox(para3); // This width makes each paragraph take three lines. var layoutArgs = new LayoutInfo(2, 2, 96, 96, FakeRenderEngine.SimulatedWidth("This is the day "), m_gm.VwGraphics, factory); root.Layout(layoutArgs); var ip1 = para1.SelectAt(1, false); var ip2 = para1.SelectAt(3, true); var range1 = new RangeSelection(ip1, ip2); Assert.That(range1.EndBeforeAnchor, Is.False); Assert.That(range1.Start, Is.EqualTo(ip1)); Assert.That(range1.End, Is.EqualTo(ip2)); PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96); var sbox1_1 = para1.FirstBox as StringBox; range1.Draw(m_gm.VwGraphics, ptrans); int topOffset = -2; // top of RcSrc for top of root box. int topYd = 2; // destination coord corresponding to top of root box. int leftXd = 2; // destination coord corresponding to left of root box. int bottomOfFirstLine = topYd + engine.SegmentHeight; int lineHeight = ptrans.MpToPixelsY(lineHeightMp); int bottomOfFirstHilite = bottomOfFirstLine + (lineHeight - engine.SegmentHeight) / 2; VerifyRangeSegmentDrawing(para1, sbox1_1, range1, topOffset, topYd, bottomOfFirstHilite); var sbox1_2 = sbox1_1.Next as StringBox; int bottomOfSecondHilite = bottomOfFirstHilite + lineHeight; VerifyRangeSegmentDrawing(para1, sbox1_2, range1, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite); var sbox1_3 = sbox1_2.Next as StringBox; int bottomOfThirddHilite = bottomOfSecondHilite + lineHeight - para1.Ascent; VerifyRangeSegmentDrawing(para1, sbox1_3, range1, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); // A two-line selection has much the same results. var ip3 = para1.SelectAt(sbox1_2.IchMin + 2, true); var range2 = new RangeSelection(ip1, ip3); range2.Draw(m_gm.VwGraphics, ptrans); VerifyRangeSegmentDrawing(para1, sbox1_1, range2, topOffset, topYd, bottomOfFirstHilite); VerifyRangeSegmentDrawing(para1, sbox1_2, range2, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite); VerifyRangeSegmentDrawing(para1, sbox1_3, range2, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); // Try multi-para selection in paras in same div. var ip2_3 = para2.SelectAt(3, false); var ip3_4 = para3.SelectAt(4, true); var range3 = new RangeSelection(ip2_3, ip3_4); range3.Draw(m_gm.VwGraphics, ptrans); var sbox2_1 = para2.FirstBox as StringBox; int topOfPara2 = topYd + para1.Height; int bottomOfFirstLineP2 = topOfPara2 + engine.SegmentHeight; int bottomOfFirstHiliteP2 = bottomOfFirstLineP2 + (lineHeight - engine.SegmentHeight) / 2; VerifyRangeSegmentDrawing(para2, sbox2_1, range3, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2); var sbox2_2 = sbox2_1.Next as StringBox; int bottomOfSecondHiliteP2 = bottomOfFirstHiliteP2 + lineHeight; VerifyRangeSegmentDrawing(para2, sbox2_2, range3, topOffset - para1.Height - lineHeight, bottomOfFirstHiliteP2, bottomOfSecondHiliteP2); var sbox2_3 = sbox2_2.Next as StringBox; int bottomOfThirddHiliteP2 = bottomOfSecondHiliteP2 + lineHeight - para2.Ascent; VerifyRangeSegmentDrawing(para2, sbox2_3, range3, topOffset - para1.Height - lineHeight * 2, bottomOfSecondHiliteP2, bottomOfThirddHiliteP2); var sbox3_1 = para3.FirstBox as StringBox; int topOfPara3 = topOfPara2 + para2.Height; var bottomOfFirstLineP3 = topOfPara3 + engine.SegmentHeight; var bottomOfFirstHiliteP3 = bottomOfFirstLineP3 + (lineHeight - engine.SegmentHeight) / 2; VerifyRangeSegmentDrawing(para3, sbox3_1, range3, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3); // Currently the other two segments of para3 will also be asked to draw it, but we've already checked how tops and bottoms // are worked out, and we don't care if these beyond-the-end segments draw it or not. Better not to test, then we can // optimize freely. // Now try a range that is (backwards and) across a div boundary var range4 = new RangeSelection(ip3_4, ip2); Assert.That(range4.EndBeforeAnchor, Is.True); Assert.That(range4.Start.SameLocation(ip2), Is.True); Assert.That(range4.End.SameLocation(ip3_4), Is.True); ClearSegmentDrawing(sbox1_3); ClearSegmentDrawing(sbox2_1); ClearSegmentDrawing(sbox3_1); range4.Draw(m_gm.VwGraphics, ptrans); // Several others should get drawn as well, but I think it's sufficient to verify tha something gets done correct in each para. VerifyRangeSegmentDrawing(para1, sbox1_3, range4, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); VerifyRangeSegmentDrawing(para2, sbox2_1, range4, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2); VerifyRangeSegmentDrawing(para3, sbox3_1, range4, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3); var range5 = new RangeSelection(ip2, ip3_4); Assert.That(range5.EndBeforeAnchor, Is.False); Assert.That(range5.Start.SameLocation(ip2), Is.True); Assert.That(range5.End.SameLocation(ip3_4), Is.True); // While we've got these selections, it's a good chance to check out GetSelectionLocation // The first one is a simple rectangle in the first string box. SetSelectionLocation(sbox1_1, 15, 20); Assert.That(range1.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(15, topYd, 20 - 15, bottomOfFirstHilite - topYd))); SetSelectionLocation(sbox1_2, 18, 25); Assert.That(range2.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(15, topYd, 25 - 15, bottomOfSecondHilite - topYd))); SetSelectionLocation(sbox3_1, 22, 27); Assert.That(range4.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(leftXd, topYd, para2.Width, bottomOfFirstHiliteP3 - topYd))); }
public void NestedDivsLayout() { var styles = new AssembledStyles(); BlockBox box1 = new BlockBox(styles, Color.Red, 72000, 36000); BlockBox box2 = new BlockBox(styles, Color.Blue, 108000, 18000); BlockBox box3 = new BlockBox(styles, Color.Orange, 72000, 18000); BlockBox box4 = new BlockBox(styles, Color.Orange, 72000, 18000); var div1 = new DivBox(styles); var div2 = new DivBox(styles); div1.AddBox(box1); div1.AddBox(box2); div2.AddBox(box3); div2.AddBox(box4); RootBox root = new RootBox(styles); root.AddBox(div1); root.AddBox(div2); LayoutInfo layoutArgs = MakeLayoutInfo(); root.Layout(layoutArgs); Assert.That(box1.Height, Is.EqualTo(48)); Assert.That(box2.Height, Is.EqualTo(24)); Assert.That(root.Height, Is.EqualTo(48 + 24 + 24 + 24)); Assert.That(box1.Left, Is.EqualTo(0)); Assert.That(box2.Left, Is.EqualTo(0)); Assert.That(box1.Top, Is.EqualTo(0)); Assert.That(box2.Top, Is.EqualTo(48)); Assert.That(div2.Top, Is.EqualTo(48 + 24)); Assert.That(box4.Top, Is.EqualTo(24)); Assert.That(box1.Width, Is.EqualTo(96)); Assert.That(box2.Width, Is.EqualTo(144)); Assert.That(root.Width, Is.EqualTo(144)); // Now try changing the size of a block. MockSite site = new MockSite(); root.Site = site; PaintTransform ptrans = new PaintTransform(2, 4, 96, 96, 0, 10, 120, 128); site.m_transform = ptrans; site.m_vwGraphics = m_gm.VwGraphics; box2.UpdateSize(144000, 36000); Assert.That(box2.Width, Is.EqualTo(96 * 2)); Assert.That(box2.Height, Is.EqualTo(48)); Assert.That(div1.Height, Is.EqualTo(96)); // two children now both 48 high. Assert.That(root.Height, Is.EqualTo(48 + 48 + 24 + 24)); // new heights of 4 children. Assert.That(root.Width, Is.EqualTo(96 * 2)); // Since it got both wider and higher, we should invalidate at least the whole current size. var bigInvalidate = root.InvalidateRect; Assert.That(site.RectsInvalidatedInRoot, Has.Member(bigInvalidate)); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 36000); Assert.That(root.Height, Is.EqualTo(48 + 48 + 24 + 24)); // unchanged this time Assert.That(root.Width, Is.EqualTo(144)); // narrower box2 still determines it // Got narrower, at least the whole old invalidate rectangle should be invalidated. Assert.That(site.RectsInvalidatedInRoot, Has.Member(bigInvalidate)); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 18000); Assert.That(root.Height, Is.EqualTo(48 + 24 + 24 + 24)); // new smaller value Assert.That(root.Width, Is.EqualTo(144)); // unchanged this time // It got shorter. We want an optimized invalidate rectangle that does not // include the top box. But it must include the space at the bottom that the root box used to occupy. // There are other possible implementations, but currently, we expect the old rectangle of box2 // to be invalidated (its in the fixmap so its own Relayout does this); // the shrinkage area at the bottom of div2; // and the area computed because div2 moved. VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48, 144, 48); // old box2 VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 24); // shrinkage of div1 // This is from the new top of div2 to its old bottom (old bottom was 48 + 48 + 24 + 24) VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 48 + 24); site.RectsInvalidated.Clear(); box2.UpdateSize(108000, 72000); Assert.That(root.Height, Is.EqualTo(48 + 96 + 24 + 24)); // new larger value Assert.That(root.Width, Is.EqualTo(144)); // unchanged this time // It got longer. We want an optimized invalidate rectangle that does not // include the top box. But it must include the space at the bottom where the root box grew. // There are other possible implementations, but currently, we expect the old rectangle of box2 // to be invalidated (it returns true from Relayout); // the growth area at the bottom of div2; // and the area computed because div2 moved. VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48, 144, 96); // new box2 VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 96 - 24); // new part of div1 occupied by box2 // This is from the old top of div2 to its new bottom (48 + 96 + 24 + 24) VerifyExpectedRectangle(site.RectsInvalidatedInRoot, 0, 48 + 24, 144, 96 + 24); }
public void Contains() { var styles = new AssembledStyles(); var runStyle = styles.WithWs(32); var root = new RootBoxFdo(styles); var para1 = MakePara(styles, runStyle, "This is the day"); var para2 = MakePara(styles, runStyle, "that the Lord has made"); var para3 = MakePara(styles, runStyle, "We will rejoice"); var div = new DivBox(styles); var para4 = MakePara(styles, runStyle, "and be glad in it"); var para5 = MakePara(styles, runStyle, ""); var para6 = MakePara(styles, runStyle, "Rejoice!"); root.AddBox(para1); root.AddBox(para2); div.AddBox(para3); div.AddBox(para4); root.AddBox(div); root.AddBox(para5); root.AddBox(para6); var run1 = para1.Source.ClientRuns[0] as StringClientRun; var ip1_0 = run1.SelectAt(para1, 0, false); var ip1_2p = run1.SelectAt(para1, 2, true); var range1_0_2 = new RangeSelection(ip1_0, ip1_2p); Assert.That(range1_0_2.Contains(ip1_0), Is.True, "selection at start of range is included"); Assert.That(range1_0_2.Contains(ip1_2p), Is.True, "selection at end of range is included"); var ip1_1p = run1.SelectAt(para1, 1, true); Assert.That(range1_0_2.Contains(ip1_1p), Is.True, "selection in middle of 1-para range is included"); var ip1_3p = run1.SelectAt(para1, 3, true); Assert.That(range1_0_2.Contains(ip1_3p), Is.False); var ip1_2a = run1.SelectAt(para1, 2, false); Assert.That(range1_0_2.Contains(ip1_2a), Is.False, "ip at end associated following is not included"); var ip1_5p = run1.SelectAt(para1, 5, true); var range1_2_5 = new RangeSelection(ip1_2a, ip1_5p); Assert.That(range1_2_5.Contains(ip1_0), Is.False, "IP before start in same para not included"); Assert.That(range1_2_5.Contains(ip1_2p), Is.False, "IP at start associated previous not included"); Assert.That(range1_2_5.Contains(ip1_2a), Is.True, "IP at start not associated previous is included"); var run2 = para2.Source.ClientRuns[0] as StringClientRun; var ip2_2p = run2.SelectAt(para2, 2, true); Assert.That(range1_2_5.Contains(ip2_2p), Is.False, "IP in following paragraph not included"); var ip2_5p = run2.SelectAt(para2, 5, true); var ip2_2a = run2.SelectAt(para2, 2, false); var range2_5_2 = new RangeSelection(ip2_5p, ip2_2a); var ip2_3a = run2.SelectAt(para2, 3, false); Assert.That(range2_5_2.Contains(ip2_3a), Is.True, "IP in middle of backwards selection is included"); Assert.That(range2_5_2.Contains(ip1_2a), Is.False, "IP in previous para not included"); var run6 = para6.Source.ClientRuns[0] as StringClientRun; var ip6_2p = run6.SelectAt(para6, 2, true); var ip1_5a = run1.SelectAt(para1, 5, false); var range1_5_6_2 = new RangeSelection(ip1_5a, ip6_2p); Assert.That(range1_5_6_2.Contains(ip1_0), Is.False, "IP before multi-para not included"); Assert.That(range1_5_6_2.Contains(ip1_3p), Is.False, "IP before multi-para not included, even with offset > end offset"); var ip6_4a = run6.SelectAt(para6, 4, false); Assert.That(range1_5_6_2.Contains(ip6_4a), Is.False, "IP after multi-para not included, even with offset < start offset"); Assert.That(range1_5_6_2.Contains(ip2_3a), Is.True, "IP middle para of multi is included"); var run4 = para4.Source.ClientRuns[0] as StringClientRun; var ip40 = run4.SelectAt(para4, 0, false); Assert.That(range1_5_6_2.Contains(ip40), Is.True, "IP in div within multi is included"); var run5 = para5.Source.ClientRuns[0] as StringClientRun; var ip50a = run5.SelectAt(para5, 0, false); Assert.That(range1_5_6_2.Contains(ip50a), Is.True, "IP in empty para within multi is included"); // I'm not absolutely sure this is the right design, but it's rather arbitrary whether an IP in an empty // paragraph associates forward or backward. If a range extends to the empty paragraph, I think it should // be included either way. var range1_5_5_0 = new RangeSelection(ip1_5a, ip50a); Assert.That(range1_5_5_0.Contains(ip50a), Is.True, "IP (ap false) in empty para at end of multi is included"); var range5_0_6_2 = new RangeSelection(ip50a, ip6_2p); Assert.That(range5_0_6_2.Contains(ip50a), Is.True, "IP (ap false) in empty para at start of multi is included"); var ip50p = run5.SelectAt(para5, 0, true); Assert.That(range1_5_5_0.Contains(ip50p), Is.True, "IP (ap true) in empty para at end of multi is included"); Assert.That(range5_0_6_2.Contains(ip50p), Is.True, "IP (ap true) in empty para at end of multi is included"); }
public void CommonContainerTests() { var styles = new AssembledStyles(); var columnWidths = new FixedColumnWidths(new[] {10}); var root1 = new RootBox(styles); var root2 = new RootBox(styles); VerifyCC(root1, root1, root1, root1, root1); VerifyCC(root2, root2, root2, root2, root2); var row1 = new RowBox(styles, columnWidths, false); var div1 = new DivBox(styles); root2.AddBox(row1); root1.AddBox(div1); VerifyCC(row1, row1, row1, row1, row1); VerifyCC(div1, div1, div1, div1, div1); VerifyCC(root1, div1, root1, root1, div1); VerifyCC(root2, row1, root2, root2, row1); var row2 = new RowBox(styles, columnWidths, false); var div2 = new DivBox(styles); root2.AddBox(row2); root1.AddBox(div2); VerifyCC(row1, row2, root2, row1, row2); VerifyCC(div1, div2, root1, div1, div2); var row3 = new RowBox(styles, columnWidths, false); var div3 = new DivBox(styles); row1.AddBox(row3); div1.AddBox(div3); VerifyCC(row1, row3, row1, row1, row3); VerifyCC(row2, row3, root2, row2, row1); VerifyCC(div1, div3, div1, div1, div3); VerifyCC(div2, div3, root1, div2, div1); var row4 = new RowBox(styles, columnWidths, false); var div4 = new DivBox(styles); row2.AddBox(row4); div2.AddBox(div4); VerifyCC(row3, row4, root2, row1, row2); VerifyCC(row1, row4, root2, row1, row2); VerifyCC(div3, div4, root1, div1, div2); VerifyCC(div1, div4, root1, div1, div2); }
public void DivClippedPaint() { var styles = new AssembledStyles(); var box1 = new FgBlockBox(styles, Color.Red, 72000, 36000); var box2 = new FgBlockBox(styles, Color.Blue, 108000, 18000); var box3 = new FgBlockBox(styles, Color.Orange, 72000, 18000); var box4 = new FgBlockBox(styles, Color.Orange, 72000, 18000); var div1 = new DivBox(styles); div1.AddBox(box1); div1.AddBox(box2); div1.AddBox(box3); div1.AddBox(box4); RootBox root = new RootBox(styles); root.AddBox(div1); LayoutInfo layoutArgs = MakeLayoutInfo(); root.Layout(layoutArgs); var rect1 = new Rectangle(0, 0, 96, 48); var rect2 = new Rectangle(0, 0, 144, 24); rect2.Offset(0, rect1.Bottom); var rect3 = new Rectangle(0, 0, 96, 24); rect3.Offset(0, rect2.Bottom); var rect4 = new Rectangle(0, 0, 96, 24); rect4.Offset(0, rect3.Bottom); var paintRects = new[] { rect1, rect2, rect3, rect4 }; VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 2000), 0, 0, paintRects); // Clipping off the top part, but not the whole, of a box does not prevent drawing it. VerifyPaint(root, new Rectangle(-1000, 10, 2000, -10 + rect4.Bottom - 10), 0, 0, paintRects); // Even clipping all but one pixel does not prevent drawing. VerifyPaint(root, new Rectangle(-1000, 47, 2000, -47 + rect3.Bottom + 1), 0, 0, paintRects); // However if we clip a bit more we should draw less var middleTwo = new[] { rect2, rect3 }; VerifyPaint(root, new Rectangle(-1000, 48, 2000, -48 + rect3.Bottom - 2), 0, 0, middleTwo); // If the clip covers just a bit of the first box we paint just that. var firstOne = new[] { rect1 }; VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 1000 + 10), 0, 0, firstOne); // If the clip covers just a bit of the last box we paint just that. var lastOne = new[] { rect4 }; VerifyPaint(root, new Rectangle(-1000, rect4.Bottom - 2, 2000, 1000), 0, 0, lastOne); // If the clip is entirely above the pile we draw nothing. VerifyPaint(root, new Rectangle(-1000, -1000, 2000, 990), 0, 0, null); // Likewise if entirely below. VerifyPaint(root, new Rectangle(-1000, rect4.Bottom + 10, 2000, 10), 0, 0, null); // Now try with simulated scrolling. Use a normal clip rectangle, but pretend the first two // and a bit boxes are scrolled off. var offset = rect2.Bottom + 10; var rect3Offset = rect3; rect3Offset.Offset(0, -offset); var rect4Offset = rect4; rect4Offset.Offset(0, -offset); var lastTwoOffset = new[] { rect3Offset, rect4Offset }; VerifyPaint(root, new Rectangle(-1000, 0, 2000, 200), 0, offset, lastTwoOffset); }
public void ComplexRangeDrawing() { var string1 = "This is the day that the Lord has made."; var string2 = "We will rejoice and be glad in it."; var string3 = "Love the Lord your God with all your heart."; var engine = new FakeRenderEngine() { Ws = 34, SegmentHeight = 13 }; var factory = new FakeRendererFactory(); factory.SetRenderer(34, engine); var runStyle = new AssembledStyles().WithWs(34); var lineHeightMp = 20000; var style = new AssembledStyles().WithLineHeight(lineHeightMp); var root = new RootBox(style); var para1 = MakePara(style, runStyle, string1); root.AddBox(para1); var div = new DivBox(style); root.AddBox(div); var para2 = MakePara(style, runStyle, string2); div.AddBox(para2); var para3 = MakePara(style, runStyle, string3); div.AddBox(para3); // This width makes each paragraph take three lines. var layoutArgs = new LayoutInfo(2, 2, 96, 96, FakeRenderEngine.SimulatedWidth("This is the day "), m_gm.VwGraphics, factory); root.Layout(layoutArgs); var ip1 = para1.SelectAt(1, false); var ip2 = para1.SelectAt(3, true); var range1 = new RangeSelection(ip1, ip2); Assert.That(range1.EndBeforeAnchor, Is.False); Assert.That(range1.Start, Is.EqualTo(ip1)); Assert.That(range1.End, Is.EqualTo(ip2)); PaintTransform ptrans = new PaintTransform(2, 2, 96, 96, 0, 0, 96, 96); var sbox1_1 = para1.FirstBox as StringBox; range1.Draw(m_gm.VwGraphics, ptrans); int topOffset = -2; // top of RcSrc for top of root box. int topYd = 2; // destination coord corresponding to top of root box. int leftXd = 2; // destination coord corresponding to left of root box. int bottomOfFirstLine = topYd + engine.SegmentHeight; int lineHeight = ptrans.MpToPixelsY(lineHeightMp); int bottomOfFirstHilite = bottomOfFirstLine + (lineHeight - engine.SegmentHeight)/2; VerifyRangeSegmentDrawing(para1, sbox1_1, range1, topOffset, topYd, bottomOfFirstHilite); var sbox1_2 = sbox1_1.Next as StringBox; int bottomOfSecondHilite = bottomOfFirstHilite + lineHeight; VerifyRangeSegmentDrawing(para1, sbox1_2, range1, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite); var sbox1_3 = sbox1_2.Next as StringBox; int bottomOfThirddHilite = bottomOfSecondHilite + lineHeight - para1.Ascent; VerifyRangeSegmentDrawing(para1, sbox1_3, range1, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); // A two-line selection has much the same results. var ip3 = para1.SelectAt(sbox1_2.IchMin + 2, true); var range2 = new RangeSelection(ip1, ip3); range2.Draw(m_gm.VwGraphics, ptrans); VerifyRangeSegmentDrawing(para1, sbox1_1, range2, topOffset, topYd, bottomOfFirstHilite); VerifyRangeSegmentDrawing(para1, sbox1_2, range2, topOffset - lineHeight, bottomOfFirstHilite, bottomOfSecondHilite); VerifyRangeSegmentDrawing(para1, sbox1_3, range2, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); // Try multi-para selection in paras in same div. var ip2_3 = para2.SelectAt(3, false); var ip3_4 = para3.SelectAt(4, true); var range3 = new RangeSelection(ip2_3, ip3_4); range3.Draw(m_gm.VwGraphics, ptrans); var sbox2_1 = para2.FirstBox as StringBox; int topOfPara2 = topYd + para1.Height; int bottomOfFirstLineP2 = topOfPara2 + engine.SegmentHeight; int bottomOfFirstHiliteP2 = bottomOfFirstLineP2 + (lineHeight - engine.SegmentHeight) / 2; VerifyRangeSegmentDrawing(para2, sbox2_1, range3, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2); var sbox2_2 = sbox2_1.Next as StringBox; int bottomOfSecondHiliteP2 = bottomOfFirstHiliteP2 + lineHeight; VerifyRangeSegmentDrawing(para2, sbox2_2, range3, topOffset - para1.Height - lineHeight, bottomOfFirstHiliteP2, bottomOfSecondHiliteP2); var sbox2_3 = sbox2_2.Next as StringBox; int bottomOfThirddHiliteP2 = bottomOfSecondHiliteP2 + lineHeight - para2.Ascent; VerifyRangeSegmentDrawing(para2, sbox2_3, range3, topOffset - para1.Height - lineHeight * 2, bottomOfSecondHiliteP2, bottomOfThirddHiliteP2); var sbox3_1 = para3.FirstBox as StringBox; int topOfPara3 = topOfPara2 + para2.Height; var bottomOfFirstLineP3 = topOfPara3 + engine.SegmentHeight; var bottomOfFirstHiliteP3 = bottomOfFirstLineP3 + (lineHeight - engine.SegmentHeight) / 2; VerifyRangeSegmentDrawing(para3, sbox3_1, range3, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3); // Currently the other two segments of para3 will also be asked to draw it, but we've already checked how tops and bottoms // are worked out, and we don't care if these beyond-the-end segments draw it or not. Better not to test, then we can // optimize freely. // Now try a range that is (backwards and) across a div boundary var range4 = new RangeSelection(ip3_4, ip2); Assert.That(range4.EndBeforeAnchor, Is.True); Assert.That(range4.Start.SameLocation(ip2), Is.True); Assert.That(range4.End.SameLocation(ip3_4), Is.True); ClearSegmentDrawing(sbox1_3); ClearSegmentDrawing(sbox2_1); ClearSegmentDrawing(sbox3_1); range4.Draw(m_gm.VwGraphics, ptrans); // Several others should get drawn as well, but I think it's sufficient to verify tha something gets done correct in each para. VerifyRangeSegmentDrawing(para1, sbox1_3, range4, topOffset - lineHeight * 2, bottomOfSecondHilite, bottomOfThirddHilite); VerifyRangeSegmentDrawing(para2, sbox2_1, range4, topOffset - para1.Height, topOfPara2, bottomOfFirstHiliteP2); VerifyRangeSegmentDrawing(para3, sbox3_1, range4, topOffset - para1.Height - para2.Height, topOfPara3, bottomOfFirstHiliteP3); var range5 = new RangeSelection(ip2, ip3_4); Assert.That(range5.EndBeforeAnchor, Is.False); Assert.That(range5.Start.SameLocation(ip2), Is.True); Assert.That(range5.End.SameLocation(ip3_4), Is.True); // While we've got these selections, it's a good chance to check out GetSelectionLocation // The first one is a simple rectangle in the first string box. SetSelectionLocation(sbox1_1, 15, 20); Assert.That(range1.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(15, topYd, 20 - 15, bottomOfFirstHilite - topYd))); SetSelectionLocation(sbox1_2, 18, 25); Assert.That(range2.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(15, topYd, 25 - 15, bottomOfSecondHilite - topYd))); SetSelectionLocation(sbox3_1, 22, 27); Assert.That(range4.GetSelectionLocation(m_gm.VwGraphics, ptrans), Is.EqualTo( new Rectangle(leftXd, topYd, para2.Width, bottomOfFirstHiliteP3 - topYd))); }
public void ValidSelections() { AssembledStyles styles = new AssembledStyles(); var clientRuns = new List <IClientRun>(); var run0 = new StringClientRun("First run", styles); var run1 = new StringClientRun("Middle run", styles); BlockBox box0 = new BlockBox(styles, Color.Red, 72000, 36000); var run2 = new StringClientRun("Last run", styles); clientRuns.Add(run0); clientRuns.Add(run1); clientRuns.Add(box0); clientRuns.Add(run2); TextSource source = new TextSource(clientRuns, null); ParaBox para0 = new ParaBox(styles, source); run0.Hookup = new LiteralStringParaHookup(para0, para0); run1.Hookup = new LiteralStringParaHookup(para0, para0); run2.Hookup = new LiteralStringParaHookup(para0, para0); DivBox div = new DivBox(styles); RootBox root = new RootBox(styles); para0.Container = div; MockGraphics graphics = new MockGraphics(); LayoutInfo layoutArgs = ParaBuilderTests.MakeLayoutInfo(100, graphics); root.Layout(layoutArgs); root.AddBox(div); var sel = para0.SelectAtStart(); root.Selection = sel; Assert.That(!root.Selection.IsValid); div.AddBox(para0); root.RemoveBoxes(div, div); div.Container = root; Assert.That(!root.Selection.IsValid); root.AddBox(div); Assert.That(root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 4; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 2; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 0; (root.Selection as InsertionPoint).StringPosition = 10; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).StringPosition = 0; run0.Hookup = null; Assert.That(!root.Selection.IsValid); run0.Hookup = new LiteralStringParaHookup(para0, para0); sel = para0.SelectAtStart(); root.Selection = sel; Assert.That(root.Selection.IsValid); }
public void ValidSelections() { AssembledStyles styles = new AssembledStyles(); var clientRuns = new List<IClientRun>(); var run0 = new StringClientRun("First run", styles); var run1 = new StringClientRun("Middle run", styles); BlockBox box0 = new BlockBox(styles, Color.Red, 72000, 36000); var run2 = new StringClientRun("Last run", styles); clientRuns.Add(run0); clientRuns.Add(run1); clientRuns.Add(box0); clientRuns.Add(run2); TextSource source = new TextSource(clientRuns, null); ParaBox para0 = new ParaBox(styles, source); run0.Hookup = new LiteralStringParaHookup(para0, para0); run1.Hookup = new LiteralStringParaHookup(para0, para0); run2.Hookup = new LiteralStringParaHookup(para0, para0); DivBox div = new DivBox(styles); RootBox root = new RootBox(styles); para0.Container = div; MockGraphics graphics = new MockGraphics(); LayoutInfo layoutArgs = ParaBuilderTests.MakeLayoutInfo(100, graphics); root.Layout(layoutArgs); root.AddBox(div); var sel = para0.SelectAtStart(); root.Selection = sel; Assert.That(!root.Selection.IsValid); div.AddBox(para0); root.RemoveBoxes(div, div); div.Container = root; Assert.That(!root.Selection.IsValid); root.AddBox(div); Assert.That(root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 4; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 2; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).Hookup.ClientRunIndex = 0; (root.Selection as InsertionPoint).StringPosition = 10; Assert.That(!root.Selection.IsValid); (root.Selection as InsertionPoint).StringPosition = 0; run0.Hookup = null; Assert.That(!root.Selection.IsValid); run0.Hookup = new LiteralStringParaHookup(para0, para0); sel = para0.SelectAtStart(); root.Selection = sel; Assert.That(root.Selection.IsValid); }