internal HitInfo(CssLineBox lineBox, int x, int y) { this.hitObject = lineBox; this.hitObjectKind = HitObjectKind.LineBox; this.localX = x; this.localY = y; }
Rectangle GetSelectionRectArea() { if (_selectedLines != null) { int j = _selectedLines.Count; if (j > 0) { CssBox ownerCssBox = null; float fx1 = 0, fy1 = 0; //left top RectangleF selArea = RectangleF.Empty; for (int i = 0; i < j; ++i) { CssLineBox line = _selectedLines[i]; if (line.OwnerBox != ownerCssBox) { ownerCssBox = line.OwnerBox; ownerCssBox.GetGlobalLocationRelativeToRoot(out fx1, out fy1); } if (i == 0) { selArea = new RectangleF(fx1, fy1 + line.CachedLineTop, line.CachedLineContentWidth, line.CacheLineHeight); } else { selArea = RectangleF.Union(selArea, new RectangleF(fx1, fy1 + line.CachedLineTop, line.CachedLineContentWidth, line.CacheLineHeight)); } } //if want to debug then send a big rect //Console.WriteLine(new Rectangle((int)selArea.X, (int)selArea.Y, (int)selArea.Width, (int)selArea.Height).ToString()); //return new Rectangle(0, 0, 800, 600); return(new Rectangle((int)selArea.Left, (int)selArea.Top, (int)selArea.Width, (int)selArea.Height)); } } return(Rectangle.Empty); }
public void PaintSelection(PaintVisitor p, CssLineBox line) { if (this.Kind == SelectionSegmentKind.FullLine) { p.FillRectangle(Color.LightGray, 0, 0, line.CachedLineContentWidth, line.CacheLineHeight); } else { p.FillRectangle( Color.LightGray, this.BeginAtPx, 0, this.WidthPx, (int)line.CacheLineHeight); } }
void InnerWalk(CssLineBox endLineBox, VisitLineDelegate del, IEnumerable <CssLineBox> lineIter) { //recursive foreach (var ln in lineIter) { this.currentVisitLineBox = ln; if (ln == endLineBox) { del(LineCoverage.EndLine, ln, null); //found endline return; } else if (this.IsWalkTargetInCurrentLineArea()) { int j = ln.RunCount; bool isOK = false; for (int i = 0; i < j && !isOK; ++i) { var run3 = ln.GetRun(i) as CssBlockRun; if (run3 == null) { continue; } //recursive here InnerWalk(endLineBox, del, GetLineWalkDownIter(this, run3.ContentBox)); if (i > 0) { del(LineCoverage.PartialLine, ln, ln.GetRun(i - 1)); } isOK = true; break; } } else { del(LineCoverage.FullLine, ln, null); } } }
internal static void GetSplitInfo(CssBox box, CssLineBox lineBox, out bool isFirstLine, out bool isLastLine) { CssLineBox firstHostLine, lastHostLine; var runList = box.Runs; if (runList == null) { firstHostLine = lastHostLine = null; } else { int j = runList.Count; firstHostLine = runList[0].HostLine; lastHostLine = runList[j - 1].HostLine; } if (firstHostLine == lastHostLine) { //is on the same line if (lineBox == firstHostLine) { isFirstLine = isLastLine = true; } else { isFirstLine = isLastLine = false; } } else { if (firstHostLine == lineBox) { isFirstLine = true; isLastLine = false; } else { isFirstLine = false; isLastLine = true; } } }
void InnerWalk(CssLineBox endLineBox, VisitLineDelegate del, IEnumerable <CssLineBox> lineIter) { //recursive foreach (CssLineBox ln in lineIter) { #if DEBUG //System.Diagnostics.Debug.WriteLine("pre_sel:" + ln.dbugId); #endif _currentVisitLineBox = ln; if (ln == endLineBox) { del(LineCoverage.EndLine, ln, null); //found endline return; } else if (this.IsWalkTargetInCurrentLineArea()) { int j = ln.RunCount; bool isOK = false; for (int i = 0; i < j && !isOK; ++i) { if (!(ln.GetRun(i) is CssBlockRun run3)) { continue; } //recursive here InnerWalk(endLineBox, del, GetLineWalkDownIter(this, run3.ContentBox)); if (i > 0) { del(LineCoverage.PartialLine, ln, ln.GetRun(i - 1)); } isOK = true; break; } } else { del(LineCoverage.FullLine, ln, null); } } }
static CssLineBox FindNearestLine(CssBox startBox, int globalY, int yRange) { CssLineBox latestLine = null; CssBox latestLineBoxOwner = null; float latestLineBoxGlobalYPos = 0; foreach (CssLineBox lineBox in BoxHitUtils.GetDeepDownLineBoxIter(startBox)) { if (lineBox.CacheLineHeight == 0) { continue; } if (latestLineBoxOwner != lineBox.OwnerBox) { //find global position of box latestLineBoxOwner = lineBox.OwnerBox; //TODO: review here , duplicate GetGlobalLocation float gx, gy; latestLineBoxOwner.GetGlobalLocation(out gx, out gy); latestLineBoxGlobalYPos = gy; } float lineGlobalBottom = lineBox.CachedLineBottom + latestLineBoxGlobalYPos; if (lineGlobalBottom <= globalY) { latestLine = lineBox; } else { latestLine = lineBox; break; } } return(latestLine); }
/// <summary> /// Recursively flows the content of the box using the inline model /// </summary> /// <param name="lay"></param> /// <param name="hostBox"></param> /// <param name="srcBox"></param> /// <param name="limitLocalRight"></param> /// <param name="firstRunStartX"></param> /// <param name="hostLine"></param> /// <param name="cx"></param> static void FlowBoxContentIntoHostLineFmtContext( LayoutVisitor lay, CssBox hostBox, //target host box that contains line formatting context CssBox srcBox, //src that has runs /splitable content) to flow into hostBox line model float limitLocalRight, float firstRunStartX, ref CssLineBox hostLine, ref float cx, ref FloatFormattingContext floatCtx) { //recursive *** //-------------------------------------------------------------------- var oX = cx; if (srcBox.HasOnlyRuns) { //condition 3 FlowRunsIntoHost(lay, hostBox, srcBox, srcBox, 0, limitLocalRight, firstRunStartX, 0, 0, CssBox.UnsafeGetRunList(srcBox), ref hostLine, ref cx ); } else { int childNumber = 0; var ifonts = lay.SampleIFonts; CssBoxCollection children = CssBox.UnsafeGetChildren(srcBox); var cNode = children.GetFirstLinkedNode(); while (cNode != null) { float leftMostSpace = 0, rightMostSpace = 0; CssBox b = cNode.Value; //if b has absolute pos then it is removed from the flow if (b.NeedComputedValueEvaluation) { b.ReEvaluateComputedValues(ifonts, hostBox); } b.MeasureRunsSize(lay); #if DEBUG if (b.Position == CssPosition.Absolute) { //should not found here! throw new NotSupportedException(); } #endif cx += leftMostSpace; if (b.CssDisplayInside == CssDisplayInside.FlowRoot)//eg. inline block { //-------- // if inside display is FlowRoot *** //--------- //outside -> inline //inside -> flow-root //can't split //create 'block-run' CssLayoutEngine.PerformContentLayout(b, lay); CssBlockRun blockRun = b.JustBlockRun; if (blockRun == null) { blockRun = new CssBlockRun(b); blockRun.SetOwner(srcBox); b.JustBlockRun = blockRun; } if (b.Width.IsEmptyOrAuto) { blockRun.SetSize(CssBox.GetLatestCachedMinWidth(b), b.VisualHeight); } else { blockRun.SetSize(b.VisualWidth, b.VisualHeight); } b.SetLocation(b.LocalX, 0); //because of inline*** FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber, limitLocalRight, firstRunStartX, leftMostSpace, rightMostSpace, new List<CssRun>() { b.JustBlockRun }, ref hostLine, ref cx); } else if (b.CssDisplayOutside == CssDisplayOutside.Block) { //warning : this code block not follow w3c spec *** CssLayoutEngine.PerformContentLayout(b, lay); CssBlockRun blockRun = b.JustBlockRun; if (blockRun == null) { blockRun = new CssBlockRun(b); blockRun.SetOwner(srcBox); b.JustBlockRun = blockRun; } //set width to full *** blockRun.SetSize(hostBox.GetClientWidth(), b.VisualHeight); b.SetLocation(b.LocalX, 0); //because of inline*** FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber, limitLocalRight, firstRunStartX, leftMostSpace, rightMostSpace, new List<CssRun>() { b.JustBlockRun }, ref hostLine, ref cx); } else if (b.HasOnlyRuns) { switch (b.Float) { default: case CssFloat.None: { FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber, limitLocalRight, firstRunStartX, leftMostSpace, rightMostSpace, CssBox.UnsafeGetRunList(b), ref hostLine, ref cx); } break; case CssFloat.Left: { //float is out of flow item //1. current line is shortening //2. add 'b' to special container *** var newAnonBlock = new CssFloatContainerBox( CssBox.UnsafeGetBoxSpec(b), b.RootGfx, CssDisplay.Block); newAnonBlock.ReEvaluateComputedValues(ifonts, hostBox); //add to abs layer hostBox.AppendToAbsoluteLayer(newAnonBlock); newAnonBlock.ResetLineBoxes(); float localX1 = 0; var line = new CssLineBox(newAnonBlock); newAnonBlock.AddLineBox(line); var newFloatCtx = new FloatFormattingContext(); FlowBoxContentIntoHostLineFmtContext(lay, newAnonBlock, b, limitLocalRight, 0, ref line, ref localX1, ref newFloatCtx); float localY = 0; int interlineSpace = 0; float maxLineWidth = 0; CssTextAlign textAlign = newAnonBlock.CssTextAlign; foreach (CssLineBox linebox in newAnonBlock.GetLineBoxIter()) { ApplyAlignment(linebox, textAlign, lay); linebox.CloseLine(lay); //*** linebox.CachedLineTop = localY; localY += linebox.CacheLineHeight + interlineSpace; if (maxLineWidth < linebox.CachedExactContentWidth) { maxLineWidth = linebox.CachedExactContentWidth; } } float hostSizeW = hostBox.VisualWidth; SetFinalInnerContentSize(newAnonBlock, maxLineWidth, localY, lay); //need to adjust line box //TODO: review here!, if (hostLine.CanDoMoreLeftOffset(newAnonBlock.InnerContentWidth, limitLocalRight)) { hostLine.DoLeftOffset(newAnonBlock.InnerContentWidth); cx = hostLine.GetRightOfLastRun(); newAnonBlock.SetLocation(floatCtx.lineLeftOffset, floatCtx.offsetFloatTop); //TODO: review top location again floatCtx.lineLeftOffset = newAnonBlock.LocalX + newAnonBlock.InnerContentWidth; } else { //newline newAnonBlock.SetLocation(hostBox.GetClientLeft(), hostLine.CalculateLineHeight()); floatCtx.offsetFloatTop = newAnonBlock.LocalY; } } break; case CssFloat.Right: { //float is out of flow item //1. create new block box and then //flow content in to this new box var newAnonBlock = new CssFloatContainerBox( CssBox.UnsafeGetBoxSpec(b), b.RootGfx, CssDisplay.Block); newAnonBlock.ReEvaluateComputedValues(ifonts, hostBox); //add to abs layer hostBox.AppendToAbsoluteLayer(newAnonBlock); newAnonBlock.ResetLineBoxes(); float localX1 = 0; var line = new CssLineBox(newAnonBlock); newAnonBlock.AddLineBox(line); var newFloatCtx = new FloatFormattingContext(); FlowBoxContentIntoHostLineFmtContext(lay, newAnonBlock, b, limitLocalRight, 0, ref line, ref localX1, ref newFloatCtx); float localY = 0; int interlineSpace = 0; float maxLineWidth = 0; CssTextAlign textAlign = newAnonBlock.CssTextAlign; foreach (CssLineBox linebox in newAnonBlock.GetLineBoxIter()) { ApplyAlignment(linebox, textAlign, lay); linebox.CloseLine(lay); //*** linebox.CachedLineTop = localY; localY += linebox.CacheLineHeight + interlineSpace; if (maxLineWidth < linebox.CachedExactContentWidth) { maxLineWidth = linebox.CachedExactContentWidth; } } SetFinalInnerContentSize(newAnonBlock, maxLineWidth, localY, lay); //todo: review here float hostSizeW = hostBox.VisualWidth; var rightOfLastRun = hostLine.GetRightOfLastRun(); if (!floatCtx.floatingOutOfLine) { if (rightOfLastRun + maxLineWidth < hostSizeW - floatCtx.lineRightOffset) { float newX = hostSizeW - (maxLineWidth + floatCtx.lineRightOffset); newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop); floatCtx.lineRightOffset = newX; floatCtx.rightFloatBox = newAnonBlock; floatCtx.floatingOutOfLine = true; } else { //start newline float newX = hostSizeW - maxLineWidth; newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop + hostLine.CalculateLineHeight()); floatCtx.lineRightOffset = newX; floatCtx.rightFloatBox = newAnonBlock; floatCtx.floatingOutOfLine = true; floatCtx.offsetFloatTop = newAnonBlock.LocalY; } } else { //out-of-line mode if (floatCtx.rightFloatBox != null) { float newX = floatCtx.rightFloatBox.LocalX - maxLineWidth; if (newX > 0) { newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop); floatCtx.lineRightOffset = newX; floatCtx.rightFloatBox = newAnonBlock; floatCtx.offsetFloatTop = newAnonBlock.LocalY; } else { //start new line newX = hostSizeW - maxLineWidth; newAnonBlock.SetLocation(newX, floatCtx.rightFloatBox.LocalY + floatCtx.rightFloatBox.InnerContentHeight); floatCtx.lineRightOffset = newX; floatCtx.rightFloatBox = newAnonBlock; floatCtx.offsetFloatTop = newAnonBlock.LocalY + newAnonBlock.InnerContentHeight; } } else { throw new NotSupportedException(); } } } break; } } else { //go deeper //recursive *** //not new lineFormatting context FlowBoxContentIntoHostLineFmtContext(lay, hostBox, b, limitLocalRight, firstRunStartX, ref hostLine, ref cx, ref floatCtx); } cx += rightMostSpace; childNumber++; //--------------------- cNode = cNode.Next; } } if (srcBox.Position == CssPosition.Relative) { //offset content relative to it 'flow' position' var left = CssValueParser.ConvertToPx(srcBox.Left, hostBox.VisualWidth, srcBox); var top = CssValueParser.ConvertToPx(srcBox.Top, hostBox.VisualWidth, srcBox); srcBox.SetLocation(srcBox.LocalX + left, srcBox.LocalY + top); } }
internal void CopyText(StringBuilder stbuilder) { //copy selected text to stbuilder //this version just copy a plain text int j = _selectedLines.Count; for (int i = 0; i < j; ++i) { CssLineBox selLine = _selectedLines[i]; SelectionSegment selSeg = selLine.SelectionSegment; switch (selSeg.Kind) { case SelectionSegmentKind.Partial: { CssRun startRun = selSeg.StartHitRun; CssRun endHitRun = selSeg.EndHitRun; bool autoFirstRun = false; bool autoLastRun = false; if (startRun == null) { startRun = selLine.GetFirstRun(); autoFirstRun = true; } if (endHitRun == null) { endHitRun = selLine.GetLastRun(); autoLastRun = true; } if (startRun == endHitRun) { if (startRun != null && _startHitRunCharIndex >= 0) { startRun.WriteContent(stbuilder, _startHitRunCharIndex, _endHitRunCharIndex - _startHitRunCharIndex); //string alltext = rr.Text; //string sub1 = alltext.Substring(_startHitRunCharIndex, _endHitRunCharIndex - _startHitRunCharIndex); //stbuilder.Append(sub1); } } else { int runCount = selLine.RunCount; bool foundStartRun = false; for (int n = 0; n < runCount; ++n) { //temp fix here! //TODO: review this for other cssrun type CssRun run = selLine.GetRun(n); if (run == startRun) { foundStartRun = true; if (autoFirstRun) { run.WriteContent(stbuilder); } else { if (_startHitRunCharIndex >= 0) { run.WriteContent(stbuilder, _startHitRunCharIndex); } } } else if (run == endHitRun) { if (autoLastRun) { run.WriteContent(stbuilder); //stbuilder.Append(alltext); } else { if (_endHitRunCharIndex >= 0) { run.WriteContent(stbuilder, 0, _endHitRunCharIndex); //string sub1 = alltext.Substring(0, _endHitRunCharIndex); //stbuilder.Append(sub1); } } //stop break; } else { if (foundStartRun) { run.WriteContent(stbuilder); //stbuilder.Append(rr.Text); } } } } } break; default: { int runCount = selLine.RunCount; for (int n = 0; n < runCount; ++n) { CssRun run = selLine.GetRun(n); run.WriteContent(stbuilder); //CssTextRun r = run as CssTextRun; //if (r != null) //{ // stbuilder.Append(r.Text); //} //else //{ //} } } break; } if (i < j - 1) { //if not lastline stbuilder.AppendLine(); } } }
///// walk down and up ///// </summary> ///// <param name="startLine"></param> ///// <returns></returns> //static IEnumerable<CssLineBox> GetLineWalkDownAndUpIter(LineWalkVisitor visitor, CssLineBox startLine) //{ // float sx, sy; // startLine.OwnerBox.GetGlobalLocation(out sx, out sy); // CssLineBox curLine = startLine; // //walk up and down the tree // CssLineBox nextline = curLine.NextLine; // while (nextline != null) // { // visitor._globalY = sy + startLine.CachedLineTop; // yield return nextline; // nextline = nextline.NextLine; // } // //-------------------- // //no next line // //then walk up *** // CssBox curBox = startLine.OwnerBox; // RETRY://*** // CssBox level1Sibling = BoxHitUtils.GetNextSibling(curBox); // while (level1Sibling != null) // { // level1Sibling.GetGlobalLocation(out sx, out sy); // visitor._globalY = sy; // //walk down // foreach (CssLineBox line in GetLineWalkDownIter(visitor, level1Sibling)) // { // yield return line; // } // level1Sibling = BoxHitUtils.GetNextSibling(level1Sibling); // } // //-------------------- // //other further sibling // //then step to parent of lineOwner // if (curBox.ParentBox != null) // { // //if has parent // //walk up*** // curBox = curBox.ParentBox; // goto RETRY; // } //} /// walk down and up /// </summary> /// <param name="startLine"></param> /// <returns></returns> static IEnumerable <CssLineBox> GetLineWalkDownAndUpIter(LineWalkVisitor visitor, CssLineBox startLine) { PointF p = new PointF(); startLine.OwnerBox.GetGlobalLocationRelativeToRoot(ref p); CssLineBox curLine = startLine; //walk up and down the tree CssLineBox nextline = curLine.NextLine; while (nextline != null) { visitor._globalY = p.Y + startLine.CachedLineTop; yield return(nextline); nextline = nextline.NextLine; } //-------------------- //no next line //then walk up *** CssBox curBox = startLine.OwnerBox; RETRY: //*** CssBox level1Sibling = BoxHitUtils.GetNextSibling(curBox); while (level1Sibling != null) { p = new PointF(); level1Sibling.GetGlobalLocationRelativeToRoot(ref p); visitor._globalY = p.Y; //walk down foreach (CssLineBox line in GetLineWalkDownIter(visitor, level1Sibling)) { yield return(line); } level1Sibling = BoxHitUtils.GetNextSibling(level1Sibling); } //-------------------- //other further sibling //then step to parent of lineOwner if (curBox.ParentBox != null) { //if has parent //walk up*** curBox = curBox.ParentBox; goto RETRY; } }
public static bool HitTest(CssBox box, float x, float y, CssBoxHitChain hitChain) { //-------------------------------------- float boxHitLocalX = x - box.LocalX; float boxHitLocalY = y - box.LocalY; bool isPointInArea = box.IsPointInArea(x, y); //---------------------------------------------------------------------- if (isPointInArea) { hitChain.AddHit(box, (int)boxHitLocalX, (int)boxHitLocalY); } //check absolute layer first *** if (box.HasAbsoluteLayer) { hitChain.PushContextBox(box); foreach (var absBox in box.GetAbsoluteChildBoxBackwardIter()) { if (HitTest(absBox, boxHitLocalX, boxHitLocalY, hitChain)) { //found hit hitChain.PopContextBox(box); return(true); } } hitChain.PopContextBox(box); } //---------------------------------------------------------------------- if (!isPointInArea) { switch (box.CssDisplay) { case Css.CssDisplay.TableRow: { foreach (var childBox in box.GetChildBoxIter()) { if (HitTest(childBox, x, y, hitChain)) { return(true); } } } break; } //exit return(false); } //---------------------------------------------------------------------- //at here point is in the area*** hitChain.PushContextBox(box); if (box.IsCustomCssBox) { //custom css box //return true= stop here if (box.CustomContentHitTest(x, y, hitChain)) { hitChain.PopContextBox(box); return(true); } } if (box.LineBoxCount > 0) { bool foundSomeLine = false; foreach (var lineBox in box.GetLineBoxIter()) { //line box not overlap if (lineBox.HitTest(boxHitLocalX, boxHitLocalY)) { foundSomeLine = true; float lineBoxLocalY = boxHitLocalY - lineBox.CachedLineTop; //2. hitChain.AddHit(lineBox, (int)boxHitLocalX, (int)lineBoxLocalY); var foundRun = BoxHitUtils.GetCssRunOnLocation(lineBox, (int)boxHitLocalX, (int)lineBoxLocalY); if (foundRun != null) { //3. hitChain.AddHit(foundRun, (int)(boxHitLocalX - foundRun.Left), (int)lineBoxLocalY); //4. go deeper for block run if (foundRun.Kind == CssRunKind.BlockRun) { var blockRun = (CssBlockRun)foundRun; CssLineBox hostLine = blockRun.HostLine; //adjust with hostline HitTest(((CssBlockRun)foundRun).ContentBox, (int)(boxHitLocalX - foundRun.Left), boxHitLocalY - hostLine.CachedLineTop, hitChain); } } //found line box hitChain.PopContextBox(box); return(true); } else if (foundSomeLine) { return(false); } } } else { //iterate in child foreach (var childBox in box.GetChildBoxIter()) { if (HitTest(childBox, boxHitLocalX, boxHitLocalY, hitChain)) { //recursive hitChain.PopContextBox(box); return(true); } } } hitChain.PopContextBox(box); return(true); }
void SetupEndHitPoint(CssBoxHitChain startChain, CssBoxHitChain endChain, ITextService ifonts) { //find global location of end point HitInfo endHit = endChain.GetLastHit(); int xposOnEndLine = 0; CssLineBox endline = null; int run_sel_offset = 0; //find endline first this.endHitRunCharIndex = 0; this.endHitRun = null; switch (endHit.hitObjectKind) { default: { throw new NotSupportedException(); } case HitObjectKind.Run: { CssRun endRun = (CssRun)endHit.hitObject; //if (endRun.Text != null && endRun.Text.Contains("Jose")) //{ //} int run_sel_index; endRun.FindSelectionPoint(ifonts, endHit.localX, out run_sel_index, out run_sel_offset); endline = endRun.HostLine; xposOnEndLine = (int)(endRun.Left + run_sel_offset); this.endHitRunCharIndex = run_sel_index; this.endHitRun = endRun; } break; case HitObjectKind.LineBox: { endline = (CssLineBox)endHit.hitObject; xposOnEndLine = endHit.localX; } break; case HitObjectKind.CssBox: { CssBox hitBox = (CssBox)endHit.hitObject; endline = FindNearestLine(hitBox, endChain.RootGlobalY, 5); xposOnEndLine = endHit.localX; } break; } #if DEBUG if (xposOnEndLine == 0) { } #endif //---------------------------------- this.selectedLines = new List <CssLineBox>(); if (startHitHostLine == endline) { this.selectedLines.Add(endline); startHitHostLine.Select(startLineBeginSelectionAtPixel, xposOnEndLine, this.startHitRun, this.startHitRunCharIndex, this.endHitRun, this.endHitRunCharIndex); return; //early exit here *** } //---------------------------------- //select on different line LineWalkVisitor lineWalkVisitor = null; int breakAtLevel; if (FindCommonGround(startChain, endChain, out breakAtLevel) && breakAtLevel > 0) { var hit1 = endChain.GetHitInfo(breakAtLevel).hitObject; var hitBlockRun = hit1 as CssBlockRun; //multiple select //1. first part if (hitBlockRun != null) { startHitHostLine.Select(startLineBeginSelectionAtPixel, (int)hitBlockRun.Left, this.startHitRun, this.startHitRunCharIndex, this.endHitRun, this.endHitRunCharIndex); selectedLines.Add(this.startHitHostLine); lineWalkVisitor = new LineWalkVisitor(hitBlockRun); } else { startHitHostLine.SelectPartialToEnd(startLineBeginSelectionAtPixel, this.startHitRun, this.startHitRunCharIndex); selectedLines.Add(this.startHitHostLine); lineWalkVisitor = new LineWalkVisitor(startHitHostLine); } } else { startHitHostLine.SelectPartialToEnd(startLineBeginSelectionAtPixel, this.startHitRun, this.startHitRunCharIndex); selectedLines.Add(this.startHitHostLine); lineWalkVisitor = new LineWalkVisitor(startHitHostLine); } lineWalkVisitor.SetWalkTargetPosition(endChain.RootGlobalX, endChain.RootGlobalY); lineWalkVisitor.Walk(endline, (lineCoverage, linebox, partialLineRun) => { switch (lineCoverage) { case LineCoverage.EndLine: { //found end line linebox.SelectPartialFromStart(xposOnEndLine, this.endHitRun, this.endHitRunCharIndex); selectedLines.Add(linebox); } break; case LineCoverage.PartialLine: { linebox.SelectPartialFromStart((int)partialLineRun.Right, this.endHitRun, this.endHitRunCharIndex); selectedLines.Add(linebox); } break; case LineCoverage.FullLine: { //check if hitpoint is in the line area linebox.SelectFull(); selectedLines.Add(linebox); } break; } }); }
/// <summary> /// Applies right alignment to the text on the linebox /// </summary> /// <param name="g"></param> /// <param name="line"></param> static void ApplyRightAlignment(CssLineBox line) { if (line.RunCount == 0) { return; } CssRun lastRun = line.GetLastRun(); float diff = line.OwnerBox.GetClientWidth() - line.GetLastRun().Right; if (diff > CSS_OFFSET_THRESHOLD) { foreach (CssRun word in line.GetRunIter()) { word.Left += diff; } } }
void SetupStartHitPoint(CssBoxHitChain startChain, IFonts ifonts) { //find global location of start point HitInfo startHit = startChain.GetLastHit(); //----------------------------- this.startHitRun = null; this.startHitRunCharIndex = 0; switch (startHit.hitObjectKind) { case HitObjectKind.Run: { CssRun run = (CssRun)startHit.hitObject; //------------------------------------------------------- int sel_index; int sel_offset; run.FindSelectionPoint(ifonts, startHit.localX, out sel_index, out sel_offset); this.startHitRunCharIndex = sel_index; //modify hitpoint this.startHitHostLine = (CssLineBox)startChain.GetHitInfo(startChain.Count - 2).hitObject; this.startLineBeginSelectionAtPixel = (int)(run.Left + sel_offset); this.startHitRun = run; } break; case HitObjectKind.LineBox: { this.startHitHostLine = (CssLineBox)startHit.hitObject; this.startLineBeginSelectionAtPixel = startHit.localX; //make global } break; case HitObjectKind.CssBox: { CssBox box = (CssBox)startHit.hitObject; //find first nearest line at point CssLineBox startHitLine = FindNearestLine(box, startChain.RootGlobalY, 5); this.startLineBeginSelectionAtPixel = 0; if (startHitLine != null) { this.startHitHostLine = startHitLine; } else { //if not found? this.startHitHostLine = null; } } break; default: { throw new NotSupportedException(); } } }
static void ApplyJustifyAlignment(CssLineBox lineBox) { if (lineBox.IsLastLine) return; float indent = lineBox.IsFirstLine ? lineBox.OwnerBox.ActualTextIndent : 0f; float runWidthSum = 0f; int runCount = 0; float availableWidth = lineBox.OwnerBox.GetClientWidth() - indent; // Gather text sum foreach (CssRun w in lineBox.GetRunIter()) { runWidthSum += w.Width; runCount++; } if (runCount == 0) return; //Avoid Zero division float spaceOfEachRun = (availableWidth - runWidthSum) / runCount; //Spacing that will be used float cX = lineBox.OwnerBox.GetClientLeft() + indent; CssRun lastRun = lineBox.GetLastRun(); foreach (CssRun run in lineBox.GetRunIter()) { run.Left = cX; cX = run.Right + spaceOfEachRun; if (run == lastRun) { run.Left = lineBox.OwnerBox.GetClientRight() - run.Width; } } }
/// <summary> /// Applies centered alignment to the text on the linebox /// </summary> /// <param name="g"></param> /// <param name="line"></param> static void ApplyCenterAlignment(CssLineBox line) { if (line.RunCount == 0) return; CssRun lastRun = line.GetLastRun(); float diff = (line.OwnerBox.GetClientWidth() - lastRun.Right) / 2; if (diff > CSS_OFFSET_THRESHOLD) { foreach (CssRun word in line.GetRunIter()) { word.Left += diff; } line.CachedLineContentWidth += diff; } }
/// <summary> /// Applies right to left direction to words /// </summary> /// <param name="blockBox"></param> /// <param name="lineBox"></param> static void ApplyRightToLeft(CssLineBox lineBox) { if (lineBox.RunCount > 0) { float left = lineBox.GetFirstRun().Left; float right = lineBox.GetLastRun().Right; foreach (CssRun run in lineBox.GetRunIter()) { float diff = run.Left - left; float w_right = right - diff; run.Left = w_right - run.Width; } } }
/// <summary> /// Applies vertical and horizontal alignment to words in lineboxes /// </summary> /// <param name="g"></param> /// <param name="lineBox"></param> static void ApplyAlignment(CssLineBox lineBox, CssTextAlign textAlign, LayoutVisitor lay) { switch (textAlign) { case CssTextAlign.Right: ApplyRightAlignment(lineBox); break; case CssTextAlign.Center: ApplyCenterAlignment(lineBox); break; case CssTextAlign.Justify: ApplyJustifyAlignment(lineBox); break; default: break; } //--------------------------------------------- // Applies vertical alignment to the linebox return; //TODO: review here lineBox.ApplyBaseline(lineBox.CalculateTotalBoxBaseLine(lay)); //--------------------------------------------- }
/// <summary> /// do layout line formatting context /// </summary> /// <param name="hostBlock"></param> /// <param name="lay"></param> public static void DoLayoutLinesContext(CssBox hostBlock, LayoutVisitor lay) { //this in line formatting context //*** hostBlock must confirm that it has all inline children hostBlock.SetHeightToZero(); hostBlock.ResetLineBoxes(); //---------------------------------------------------------------------------------------- float limitLocalRight = hostBlock.VisualWidth - (hostBlock.ActualPaddingRight + hostBlock.ActualBorderRightWidth); float localX = hostBlock.ActualTextIndent + hostBlock.ActualPaddingLeft + hostBlock.ActualBorderLeftWidth; float localY = hostBlock.ActualPaddingTop + hostBlock.ActualBorderTopWidth; //---------------------------------------------------------------------------------------- if (lay.HasFloatBoxInContext) { var recentLeftFloatBox = lay.LatestLeftFloatBox; var recentRightFloatBox = lay.LatestRightFloatBox; var latestSibling = lay.LatestSiblingBox; if (latestSibling != null) { //check latest sibling first if (hostBlock.Float == CssFloat.None) { if (recentLeftFloatBox != null) { if (hostBlock.LocalY < recentLeftFloatBox.LocalVisualBottom) { localX = recentLeftFloatBox.LocalVisualRight; } } else { } } } else { if (hostBlock.Float == CssFloat.None) { if (recentLeftFloatBox != null) { localX = recentLeftFloatBox.LocalVisualRight; } if (recentRightFloatBox != null) { limitLocalRight = recentRightFloatBox.LocalX; } } //check if need newline or not } } int interlineSpace = 0; //First line box var line = new CssLineBox(hostBlock); hostBlock.AddLineBox(line); //**** var floatCtx = new FloatFormattingContext(); FlowBoxContentIntoHostLineFmtContext(lay, hostBlock, hostBlock, limitLocalRight, localX, ref line, ref localX, ref floatCtx); //**** // if width is not restricted we need to lower it to the actual width if (hostBlock.VisualWidth + lay.ContainerBlockGlobalX >= CssBoxConstConfig.BOX_MAX_RIGHT) { float newWidth = localX + hostBlock.ActualPaddingRight + hostBlock.ActualBorderRightWidth;// CssBox.MAX_RIGHT - (args.ContainerBlockGlobalX + blockBox.LocalX); if (newWidth <= CSS_OFFSET_THRESHOLD) { newWidth = CSS_OFFSET_THRESHOLD; } hostBlock.SetVisualWidth(newWidth); } //--------------------- float maxLineWidth = 0; if (hostBlock.CssDirection == CssDirection.Rtl) { CssTextAlign textAlign = hostBlock.CssTextAlign; foreach (CssLineBox linebox in hostBlock.GetLineBoxIter()) { ApplyAlignment(linebox, textAlign, lay); ApplyRightToLeft(linebox); //*** linebox.CloseLine(lay); //*** linebox.CachedLineTop = localY; localY += linebox.CacheLineHeight + interlineSpace; // + interline space? if (maxLineWidth < linebox.CachedExactContentWidth) { maxLineWidth = linebox.CachedExactContentWidth; } } } else { CssTextAlign textAlign = hostBlock.CssTextAlign; foreach (CssLineBox linebox in hostBlock.GetLineBoxIter()) { ApplyAlignment(linebox, textAlign, lay); linebox.CloseLine(lay); //*** linebox.CachedLineTop = localY; localY += linebox.CacheLineHeight + interlineSpace; if (maxLineWidth < linebox.CachedExactContentWidth) { maxLineWidth = linebox.CachedExactContentWidth; } } } hostBlock.SetVisualHeight(localY + hostBlock.ActualPaddingBottom + hostBlock.ActualBorderBottomWidth); //final SetFinalInnerContentSize(hostBlock, maxLineWidth, hostBlock.VisualHeight, lay); }
public LineWalkVisitor(CssLineBox startLineBox) { this.startLineBox = startLineBox; float endElemX = 0, endElemY = 0; startLineBox.OwnerBox.GetGlobalLocation(out endElemX, out endElemY); this.globalX = endElemX; this.globalY = endElemY + startLineBox.CachedLineTop; }
internal static CssRun GetCssRunOnLocation(CssLineBox lineBox, int x, int y) { foreach (CssRun word in lineBox.GetRunIter()) { // add word spacing to word width so sentance won't have hols in it when moving the mouse var rect = word.Rectangle; //rect.Width += word.OwnerBox.ActualWordSpacing; if (rect.Contains(x, y)) { return word; } } return null; }
public void Walk(CssLineBox endLineBox, VisitLineDelegate del) { //2 cases : //1. start with BlockRun //2. start with LineBox InnerWalk(endLineBox, del, (startBlockRun != null) ? GetLineWalkDownIter(this, startBlockRun.ContentBox) : GetLineWalkDownAndUpIter(this, startLineBox)); }
void InnerWalk(CssLineBox endLineBox, VisitLineDelegate del, IEnumerable<CssLineBox> lineIter) { //recursive foreach (var ln in lineIter) { this.currentVisitLineBox = ln; if (ln == endLineBox) { del(LineCoverage.EndLine, ln, null); //found endline return; } else if (this.IsWalkTargetInCurrentLineArea()) { int j = ln.RunCount; bool isOK = false; for (int i = 0; i < j && !isOK; ++i) { var run3 = ln.GetRun(i) as CssBlockRun; if (run3 == null) continue; //recursive here InnerWalk(endLineBox, del, GetLineWalkDownIter(this, run3.ContentBox)); if (i > 0) { del(LineCoverage.PartialLine, ln, ln.GetRun(i - 1)); } isOK = true; break; } } else { del(LineCoverage.FullLine, ln, null); } } }
internal void AddHit(CssLineBox lineBox, int x, int y) { //position x,y relate with (0,0) of its linebox hitInfoList.Add(new HitInfo(lineBox, x, y)); }
/// walk down and up /// </summary> /// <param name="startLine"></param> /// <returns></returns> static IEnumerable<CssLineBox> GetLineWalkDownAndUpIter(LineWalkVisitor visitor, CssLineBox startLine) { float sx, sy; startLine.OwnerBox.GetGlobalLocation(out sx, out sy); CssLineBox curLine = startLine; //walk up and down the tree CssLineBox nextline = curLine.NextLine; while (nextline != null) { visitor.globalY = sy + startLine.CachedLineTop; yield return nextline; nextline = nextline.NextLine; } //-------------------- //no next line //then walk up *** CssBox curBox = startLine.OwnerBox; RETRY: CssBox level1Sibling = BoxHitUtils.GetNextSibling(curBox); while (level1Sibling != null) { level1Sibling.GetGlobalLocation(out sx, out sy); visitor.globalY = sy; //walk down foreach (var line in GetLineWalkDownIter(visitor, level1Sibling)) { yield return line; } level1Sibling = BoxHitUtils.GetNextSibling(level1Sibling); } //-------------------- //other further sibling //then step to parent of lineOwner if (curBox.ParentBox != null) { //if has parent //walk up*** curBox = curBox.ParentBox; goto RETRY; } }
/// walk down and up /// </summary> /// <param name="startLine"></param> /// <returns></returns> static IEnumerable <CssLineBox> GetLineWalkDownAndUpIter(LineWalkVisitor visitor, CssLineBox startLine) { float sx, sy; startLine.OwnerBox.GetGlobalLocation(out sx, out sy); CssLineBox curLine = startLine; //walk up and down the tree CssLineBox nextline = curLine.NextLine; while (nextline != null) { visitor.globalY = sy + startLine.CachedLineTop; yield return(nextline); nextline = nextline.NextLine; } //-------------------- //no next line //then walk up *** CssBox curBox = startLine.OwnerBox; RETRY: CssBox level1Sibling = BoxHitUtils.GetNextSibling(curBox); while (level1Sibling != null) { level1Sibling.GetGlobalLocation(out sx, out sy); visitor.globalY = sy; //walk down foreach (var line in GetLineWalkDownIter(visitor, level1Sibling)) { yield return(line); } level1Sibling = BoxHitUtils.GetNextSibling(level1Sibling); } //-------------------- //other further sibling //then step to parent of lineOwner if (curBox.ParentBox != null) { //if has parent //walk up*** curBox = curBox.ParentBox; goto RETRY; } }
internal void AddHit(CssLineBox lineBox, int x, int y) { //position x,y relate with (0,0) of its linebox _hitInfoList.Add(new HitInfo(lineBox, x, y)); }
void SetupEndHitPoint(CssBoxHitChain startChain, CssBoxHitChain endChain, ITextService textService) { //find global location of end point HitInfo endHit = endChain.GetLastHit(); int xposOnEndLine = 0; CssLineBox endline = null; //find endline first _endHitRunCharIndex = 0; _endHitRun = null; switch (endHit.hitObjectKind) { default: { throw new NotSupportedException(); } case HitObjectKind.Run: { CssRun endRun = (CssRun)endHit.hitObject; #if DEBUG //if (endRun.Text != null && endRun.Text.Contains("Jose")) //{ //} if (endHit.localX > 23) { } System.Diagnostics.Debug.WriteLine(endHit.localX); #endif endRun.FindSelectionPoint(textService, endHit.localX, out int run_sel_index, out int run_sel_offset); endline = endRun.HostLine; xposOnEndLine = (int)(endRun.Left + run_sel_offset); _endHitRunCharIndex = run_sel_index; #if DEBUG System.Diagnostics.Debug.WriteLine(_endHitRunCharIndex); #endif _endHitRun = endRun; } break; case HitObjectKind.LineBox: { endline = (CssLineBox)endHit.hitObject; xposOnEndLine = endHit.localX; } break; case HitObjectKind.CssBox: { CssBox hitBox = (CssBox)endHit.hitObject; endline = FindNearestLine(hitBox, endChain.RootGlobalY, 5); xposOnEndLine = endHit.localX; } break; } #if DEBUG if (xposOnEndLine == 0) { } #endif //---------------------------------- _selectedLines = new List <CssLineBox>(); if (_startHitHostLine == endline) { _selectedLines.Add(endline); _startHitHostLine.Select(_startLineBeginSelectionAtPixel, xposOnEndLine, _startHitRun, _startHitRunCharIndex, _endHitRun, _endHitRunCharIndex); return; //early exit here *** } //---------------------------------- //select on different line LineWalkVisitor lineWalkVisitor = null; if (FindCommonGround(startChain, endChain, out int breakAtLevel) && breakAtLevel > 0) { CssBlockRun hitBlockRun = endChain.GetHitInfo(breakAtLevel).hitObject as CssBlockRun; //multiple select //1. first part if (hitBlockRun != null) { _startHitHostLine.Select(_startLineBeginSelectionAtPixel, (int)hitBlockRun.Left, _startHitRun, _startHitRunCharIndex, _endHitRun, _endHitRunCharIndex); _selectedLines.Add(_startHitHostLine); lineWalkVisitor = new LineWalkVisitor(hitBlockRun); } else { _startHitHostLine.SelectPartialToEnd(_startLineBeginSelectionAtPixel, _startHitRun, _startHitRunCharIndex); _selectedLines.Add(_startHitHostLine); lineWalkVisitor = new LineWalkVisitor(_startHitHostLine); } } else { _startHitHostLine.SelectPartialToEnd(_startLineBeginSelectionAtPixel, _startHitRun, _startHitRunCharIndex); _selectedLines.Add(_startHitHostLine); lineWalkVisitor = new LineWalkVisitor(_startHitHostLine); } lineWalkVisitor.SetWalkTargetPosition(endChain.RootGlobalX, endChain.RootGlobalY); #if DEBUG int dbugExpectedId = 1; #endif lineWalkVisitor.Walk(endline, (lineCoverage, linebox, partialLineRun) => { #if DEBUG //System.Diagnostics.Debug.WriteLine("sel:" + linebox.dbugId); if (dbugExpectedId != linebox.dbugId) { } dbugExpectedId++; #endif switch (lineCoverage) { case LineCoverage.EndLine: { //found end line linebox.SelectPartialFromStart(xposOnEndLine, _endHitRun, _endHitRunCharIndex); _selectedLines.Add(linebox); } break; case LineCoverage.PartialLine: { linebox.SelectPartialFromStart((int)partialLineRun.Right, _endHitRun, _endHitRunCharIndex); _selectedLines.Add(linebox); } break; case LineCoverage.FullLine: { //check if hitpoint is in the line area linebox.SelectFull(); _selectedLines.Add(linebox); } break; } }); }
public static bool HitTest(CssBox box, float x, float y, CssBoxHitChain hitChain) { #if DEBUG //if (box.ViewportY != 0 && hitChain.debugEventPhase == CssBoxHitChain.dbugEventPhase.MouseDown) //{ //} #endif //-------------------------------------- bool isPointInArea = box.IsPointInArea(x, y); float boxHitLocalX = x - box.LocalX; //** float boxHitLocalY = y - box.LocalY; //** //---------------------------------------------------------------------- if (isPointInArea) { hitChain.AddHit(box, (int)boxHitLocalX, (int)boxHitLocalY); } //---------------------------------------------------------------------- //enter children space -> offset with its viewport boxHitLocalX += box.ViewportX; boxHitLocalY += box.ViewportY; //check absolute layer first *** if (box.HasAbsoluteLayer) { hitChain.PushContextBox(box); foreach (CssBox absBox in box.GetAbsoluteChildBoxBackwardIter()) { if (HitTest(absBox, boxHitLocalX, boxHitLocalY, hitChain)) { //found hit hitChain.PopContextBox(box); return(true); } } hitChain.PopContextBox(box); } //---------------------------------------------------------------------- if (!isPointInArea) { switch (box.CssDisplay) { case Css.CssDisplay.TableRow: { foreach (CssBox childBox in box.GetChildBoxIter()) { if (HitTest(childBox, boxHitLocalX, boxHitLocalY, hitChain)) { return(true); } } } break; } //exit return(false); } //---------------------------------------------------------------------- //at here point is in the area*** hitChain.PushContextBox(box); if (box.IsCustomCssBox) { //custom css box //return true= stop here if (box.CustomContentHitTest(boxHitLocalX, boxHitLocalY, hitChain)) { hitChain.PopContextBox(box); return(true); } } if (box.LineBoxCount > 0) { bool foundSomeLine = false; foreach (CssLineBox lineBox in box.GetLineBoxIter()) { //line box not overlap if (lineBox.HitTest(boxHitLocalX, boxHitLocalY)) { foundSomeLine = true; float lineBoxLocalY = boxHitLocalY - lineBox.CachedLineTop; //2. hitChain.AddHit(lineBox, (int)boxHitLocalX, (int)lineBoxLocalY); CssRun foundRun = BoxHitUtils.GetCssRunOnLocation(lineBox, (int)boxHitLocalX, (int)lineBoxLocalY); //CssRun foundRun = BoxHitUtils.GetCssRunOnLocation(lineBox, (int)x, (int)y); if (foundRun != null) { //3. hitChain.AddHit(foundRun, (int)(boxHitLocalX - foundRun.Left), (int)lineBoxLocalY); //4. go deeper for block run if (foundRun.Kind == CssRunKind.BlockRun) { CssBlockRun blockRun = (CssBlockRun)foundRun; CssLineBox hostLine = blockRun.HostLine; //adjust with hostline HitTest(blockRun.ContentBox, (int)(boxHitLocalX + blockRun.ContentBox.LocalX - foundRun.Left), (int)(boxHitLocalY - hostLine.CachedLineTop), hitChain); } } //found line box hitChain.PopContextBox(box); return(true); } else if (foundSomeLine) { return(false); } } } else { //iterate in child //foreach (var childBox in box.GetChildBoxIter()) foreach (CssBox childBox in box.GetChildBoxBackwardIter()) { if (HitTest(childBox, boxHitLocalX, boxHitLocalY, hitChain)) { //recursive hitChain.PopContextBox(box); return(true); } } } hitChain.PopContextBox(box); return(true); }
public static void SelectFull(this CssLineBox lineBox) { //full line selection lineBox.SelectionSegment = SelectionSegment.FullLine; }
internal void AddLineBox(CssLineBox linebox) { linebox.linkedNode = this._clientLineBoxes.AddLast(linebox); }
internal static void SetHostLine(CssRun run, CssLineBox hostline) { run._hostline = hostline; }
//--------------------------- static void FlowRunsIntoHost(LayoutVisitor lay, CssBox hostBox, CssBox splitableBox, CssBox b, int childNumber, //child number of b float limitRight, float firstRunStartX, float leftMostSpace, float rightMostSpace, List<CssRun> runs, ref CssLineBox hostLine, ref float cx) { //flow runs into hostLine, create new line if need bool wrapNoWrapBox = false; CssWhiteSpace bWhiteSpace = b.WhiteSpace; bool hostBoxIsB = hostBox == b; if (bWhiteSpace == CssWhiteSpace.NoWrap && cx > firstRunStartX) { var tmpRight = cx; for (int i = runs.Count - 1; i >= 0; --i) { tmpRight += runs[i].Width; } //----------------------------------------- if (tmpRight > limitRight) { wrapNoWrapBox = true; } } //----------------------------------------------------- int lim = runs.Count - 1; for (int i = 0; i <= lim; ++i) { var run = runs[i]; //--------------------------------------------------- //check if need to start new line ? if ((cx + run.Width + rightMostSpace > limitRight && bWhiteSpace != CssWhiteSpace.NoWrap && bWhiteSpace != CssWhiteSpace.Pre && (bWhiteSpace != CssWhiteSpace.PreWrap || !run.IsSpaces)) || run.IsLineBreak || wrapNoWrapBox) { wrapNoWrapBox = false; //once! //------------------------------- //create new line *** hostLine = new CssLineBox(hostBox); hostBox.AddLineBox(hostLine); //reset x pos for new line cx = firstRunStartX; // handle if line is wrapped for the first text element where parent has left margin/padding if (childNumber == 0 && //b is first child of splitable box ('b' == splitableBox.GetFirstChild()) !run.IsLineBreak && (i == 0 || splitableBox.ParentBox.IsBlock))//this run is first run of 'b' (run == b.FirstRun) { //TODO: review here again!!!! //cx += splitableBox.ActualMarginLeft + // splitableBox.ActualBorderLeftWidth + // splitableBox.ActualPaddingLeft; } if (run.IsSolidContent || i == 0) { cx += leftMostSpace; } } //--------------------------------------------------- if (run.IsSpaces && hostLine.RunCount == 0) { //not add continue; } //--------------------------------------------------- hostLine.AddRun(run); //*** if (lim == 0) { //single one if (!hostBoxIsB) { cx += b.ActualPaddingLeft; } run.SetLocation(cx, 0); cx += run.Width + b.ActualPaddingRight; } else { if (i == 0) { //first if (!hostBoxIsB) { cx += b.ActualPaddingLeft; } run.SetLocation(cx, 0); cx = run.Right; } else if (i == lim) { run.SetLocation(cx, 0); cx += run.Width + b.ActualPaddingRight; } else { run.SetLocation(cx, 0); cx = run.Right; } } //--------------------------------------------------- //move current_line_x to right of run //cx = run.Right; } }
protected virtual void PaintImp(PaintVisitor p) { //if (this.dbugMark2 == 10 || this.dbugMark2 == 12) //{ //} Css.CssDisplay display = this.CssDisplay; if (display == Css.CssDisplay.TableCell && this.EmptyCells == Css.CssEmptyCell.Hide && this.IsSpaceOrEmpty) { return; } #if DEBUG p.dbugEnterNewContext(this, PaintVisitor.PaintVisitorContextName.Init); #endif //----------------------------------------------- bool hasPrevClip = false; RectangleF prevClip = RectangleF.Empty; p.EnterNewLatePaintContext(); //--------------------------------------------- //if (display != Css.CssDisplay.Inline || // this.Position == Css.CssPosition.Absolute || // this.Position == Css.CssPosition.Fixed) if (this._renderBGAndBorder) { RectangleF bound = new RectangleF(0, 0, this.VisualWidth, this.VisualHeight); PaintBackground(p, bound, true, true); if (this.HasSomeVisibleBorder) { p.PaintBorders(this, bound, true, true); } #if DEBUG dbugPaint(p, bound); #endif } //--------------------------------------------- if (this.LineBoxCount > 0) { float viewport_top = p.ViewportTop; float viewport_bottom = p.ViewportBottom; int drawState = 0; var c_lineNode = this._clientLineBoxes.First; while (c_lineNode != null) { CssLineBox line = c_lineNode.Value; if (line.CachedLineBottom >= viewport_top && line.CachedLineTop <= viewport_bottom) { #if DEBUG dbugCounter.dbugLinePaintCount++; #endif drawState = 1;//drawing in viewport area int cX = p.CanvasOriginX; int cy = p.CanvasOriginY; p.SetCanvasOrigin(cX, cy + (int)line.CachedLineTop); //1. line.PaintBackgroundAndBorder(p); if (line.SelectionSegment != null) { line.SelectionSegment.PaintSelection(p, line); } //2. line.PaintRuns(p); //3. line.PaintDecoration(p); #if DEBUG line.dbugPaintRuns(p); #endif p.SetCanvasOrigin(cX, cy);//back } else if (drawState == 1) { //outof viewport -> break break; } //---------------------------------------- c_lineNode = c_lineNode.Next; } } else { if (this.HasContainingBlockProperty) { p.PushContaingBlock(this); int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; var node = this._aa_boxes.GetFirstLinkedNode(); while (node != null) { CssBox b = node.Value; if (b.CssDisplay == Css.CssDisplay.None) { node = node.Next; continue; } else if (b.IsOutOfFlowBox) { // p.AddToLatePaintList(b); node = node.Next; continue; } //move to left-top of client box p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); if (b.decorator != null) { b.decorator.Paint(b, p); } if (b.HasClipArea) { if (p.PushLocalClipArea(b.VisualWidth, b.VisualHeight)) { b.Paint(p); } p.PopLocalClipArea(); } else { b.Paint(p); } node = node.Next; } p.SetCanvasOrigin(ox, oy); p.PopContainingBlock(); } else { //if not int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; var node = this._aa_boxes.GetFirstLinkedNode(); while (node != null) { CssBox b = node.Value; if (b.CssDisplay == Css.CssDisplay.None) { node = node.Next; continue; } p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); b.Paint(p); node = node.Next; } p.SetCanvasOrigin(ox, oy); } } //------------------------------------------ //debug //var clientLeft = this.ClientLeft; //g.DrawRectangle(Pens.GreenYellow, 0, 0, 5, 10); //g.DrawRectangle(Pens.HotPink, this.ClientRight - 5, 0, 5, 10); //------------------------------------------ if (this.HasAbsoluteLayer) { p.PushContaingBlock(this); int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; var node = this._absPosLayer.GetFirstLinkedNode(); while (node != null) { CssBox b = node.Value; if (b.CssDisplay == Css.CssDisplay.None) { node = node.Next; continue; } p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); b.Paint(p); node = node.Next; } p.SetCanvasOrigin(ox, oy); p.PopContainingBlock(); } if (p.LatePaintItemCount > 0) { //late paint -> floatBox Rectangle latestClipRect = p.CurrentClipRect; p.PopLocalClipArea(); //temp p.PushContaingBlock(this); int j = p.LatePaintItemCount; int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; for (int i = 0; i < j; ++i) { CssBox box = p.GetLatePaintItem(i); if (box.CssDisplay == Css.CssDisplay.None) { continue; } p.SetCanvasOrigin(ox + (int)box.LocalX, oy + (int)box.LocalY); box.Paint(p); p.SetCanvasOrigin(ox, oy); } p.PopContainingBlock(); p.PushLocalClipArea(latestClipRect.Width, latestClipRect.Height);//push back } p.ExitCurrentLatePaintContext(); //must! , if (hasPrevClip) { p.PopLocalClipArea(); } #if DEBUG p.dbugExitContext(); #endif }
protected virtual void PaintImp(PaintVisitor p) { #if DEBUG //if (__aa_dbugId == 6) //{ //} //if (this.dbugMark2 == 10 || this.dbugMark2 == 12) //{ //} #endif Css.CssDisplay display = this.CssDisplay; // if (display == Css.CssDisplay.TableCell && this.EmptyCells == Css.CssEmptyCell.Hide && this.IsSpaceOrEmpty) { return; } #if DEBUG p.dbugEnterNewContext(this, PaintVisitor.PaintVisitorContextName.Init); #endif Color prevBgColorHint = p.CurrentSolidBackgroundColorHint; //----------------------------------------------- bool hasPrevClip = false; RectangleF prevClip = RectangleF.Empty; p.EnterNewLatePaintContext(); //--------------------------------------------- //if (display != Css.CssDisplay.Inline || // this.Position == Css.CssPosition.Absolute || // this.Position == Css.CssPosition.Fixed) if (_renderBGAndBorder) { RectangleF bounds = new RectangleF(0, 0, this.VisualWidth, this.VisualHeight); PaintBackground(p, bounds, true, true); if (this.HasSomeVisibleBorder) { p.PaintBorders(this, bounds, true, true); } #if DEBUG dbugPaint(p, bounds); #endif } //--------------------------------------------- if (this.LineBoxCount > 0) { float viewport_top = p.ViewportTop; float viewport_bottom = p.ViewportBottom; int drawState = 0; var c_lineNode = _clientLineBoxes.First; while (c_lineNode != null) { CssLineBox line = c_lineNode.Value; if (line.CachedLineBottom >= viewport_top && line.CachedLineTop <= viewport_bottom) { Rectangle currentClipRect = p.CurrentClipRect; drawState = 1;//drawing in viewport area #if DEBUG //System.Diagnostics.Debug.WriteLine("clip_rect:" + currentClipRect); dbugCounter.dbugLinePaintCount++; #endif int cX = p.CanvasOriginX; int cy = p.CanvasOriginY; int newCy = cy + (int)line.CachedLineTop; if (newCy <= (cy + currentClipRect.Bottom) && newCy + line.CacheLineHeight >= (cy + currentClipRect.Top)) { p.SetCanvasOrigin(cX, newCy); //1. line.PaintBackgroundAndBorder(p); SelectionSegment selSegment = line.SelectionSegment; if (selSegment != null) { switch (selSegment.Kind) { case SelectionSegmentKind.FullLine: { Color prevColor2 = p.CurrentSolidBackgroundColorHint; //save2 p.CurrentSolidBackgroundColorHint = p.CssBoxSelectionColor; selSegment.PaintSelection(p, line); line.PaintRuns(p); p.CurrentSolidBackgroundColorHint = prevColor2; //restore2 } break; case SelectionSegmentKind.PartialBegin: case SelectionSegmentKind.SingleLine: case SelectionSegmentKind.PartialEnd: { //TODO: review here again*** //partial line //[A] line.PaintRuns(p); //normal line //----- //[B] //selection part with clip rect Color prevColor2 = p.CurrentSolidBackgroundColorHint; //save2 //p.CurrentSolidBackgroundColorHint = prevBgColorHint; int xpos = selSegment.BeginAtPx; int w = selSegment.WidthPx; Rectangle clipRect = p.CurrentClipRect; p.SetClipArea(xpos, 0, w, (int)line.CacheLineHeight); selSegment.PaintSelection(p, line); p.CurrentSolidBackgroundColorHint = p.CssBoxSelectionColor; line.PaintRuns(p); p.SetClipArea(clipRect.X, clipRect.Top, clipRect.Width, clipRect.Height); //restore p.CurrentSolidBackgroundColorHint = prevColor2; //restore2 } break; } } else { //2. line.PaintRuns(p); } //3. line.PaintDecoration(p); #if DEBUG line.dbugPaintRuns(p); #endif p.SetCanvasOrigin(cX, cy);//back } } else if (drawState == 1) { //outof viewport -> break break; } //---------------------------------------- c_lineNode = c_lineNode.Next; } } else { if (this.HasContainingBlockProperty) { p.PushContaingBlock(this); int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; var node = _aa_boxes.GetFirstLinkedNode(); while (node != null) { CssBox b = node.Value; if (b.CssDisplay == Css.CssDisplay.None || b.IsAddedToAbsoluteLayer) { node = node.Next; continue; } else if (b.IsOutOfFlowBox) { // p.AddToLatePaintList(b); node = node.Next; continue; } //move to left-top of client box p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); if (b._decorator != null) { b._decorator.Paint(b, p); } if (b.HasClipArea) { if (p.PushLocalClipArea(b.VisualWidth, b.VisualHeight)) { CssBox.Paint(b, p); p.PopLocalClipArea(); } } else { CssBox.Paint(b, p); } node = node.Next; } p.SetCanvasOrigin(ox, oy); p.PopContainingBlock(); } else { //if not int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; var node = _aa_boxes.GetFirstLinkedNode(); while (node != null) { CssBox b = node.Value; if (b.CssDisplay == Css.CssDisplay.None || b.IsAddedToAbsoluteLayer) { node = node.Next; continue; } p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); CssBox.Paint(b, p); node = node.Next; } p.SetCanvasOrigin(ox, oy); } } //------------------------------------------ //debug //var clientLeft = this.ClientLeft; //g.DrawRectangle(Pens.GreenYellow, 0, 0, 5, 10); //g.DrawRectangle(Pens.HotPink, this.ClientRight - 5, 0, 5, 10); //------------------------------------------ if (this.HasAbsoluteLayer) { p.PushContaingBlock(this); int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; int j = _absPosLayer.Count; for (int i = 0; i < j; ++i) { CssBox b = _absPosLayer.GetBox(i); if (b.CssDisplay == Css.CssDisplay.None) { continue; } p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); CssBox.Paint(b, p); } //var node = _absPosLayer.GetFirstLinkedNode(); //while (node != null) //{ // CssBox b = node.Value; // if (b.CssDisplay == Css.CssDisplay.None) // { // node = node.Next; // continue; // } // p.SetCanvasOrigin(ox + (int)b.LocalX, oy + (int)b.LocalY); // b.Paint(p); // node = node.Next; //} p.SetCanvasOrigin(ox, oy); p.PopContainingBlock(); } if (p.LatePaintItemCount > 0) { //late paint -> floatBox Rectangle latestClipRect = p.CurrentClipRect; p.PopLocalClipArea(); //temp p.PushContaingBlock(this); int j = p.LatePaintItemCount; int ox = p.CanvasOriginX; int oy = p.CanvasOriginY; for (int i = 0; i < j; ++i) { CssBox box = p.GetLatePaintItem(i); if (box.CssDisplay == Css.CssDisplay.None) { continue; } p.SetCanvasOrigin(ox + (int)box.LocalX, oy + (int)box.LocalY); CssBox.Paint(box, p); p.SetCanvasOrigin(ox, oy); } p.PopContainingBlock(); p.PushLocalClipArea(latestClipRect.Width, latestClipRect.Height);//push back } p.ExitCurrentLatePaintContext(); //must! , if (hasPrevClip) { p.PopLocalClipArea(); } p.CurrentSolidBackgroundColorHint = prevBgColorHint; #if DEBUG p.dbugExitContext(); #endif }
internal void AddLineBox(CssLineBox linebox) { linebox.linkedNode = _clientLineBoxes.AddLast(linebox); }