Skip to content

Commit ceaad77

Browse files
author
ArthurHub
committed
* refactor clipping to use push/pop scheme
* handle clipping in WPF * handle clipping in PdfSharp
1 parent 593b1d2 commit ceaad77

14 files changed

Lines changed: 108 additions & 140 deletions

File tree

Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
// "The Art of War"
1212

1313
using System;
14-
using System.Drawing;
1514
using HtmlRenderer.Adapters;
1615
using HtmlRenderer.Adapters.Entities;
1716
using HtmlRenderer.Core.Utils;
@@ -59,29 +58,27 @@ static GraphicsAdapter()
5958
/// <param name="g">the win forms graphics object to use</param>
6059
/// <param name="releaseGraphics">optional: if to release the graphics object on dispose (default - false)</param>
6160
public GraphicsAdapter(XGraphics g, bool releaseGraphics = false)
62-
: base(PdfSharpAdapter.Instance)
61+
: base(PdfSharpAdapter.Instance, new RRect(0, 0, double.MaxValue, double.MaxValue))
6362
{
6463
ArgChecker.AssertArgNotNull(g, "g");
6564

6665
_g = g;
6766
_releaseGraphics = releaseGraphics;
6867
}
6968

70-
public override RRect GetClip()
69+
public override void PopClip()
7170
{
72-
RectangleF clip = _g.Graphics.ClipBounds;
73-
return Utils.Convert(clip);
71+
_g.Restore();
7472
}
7573

76-
public override void SetClipReplace(RRect rect)
74+
public override void PushClip(RRect rect)
7775
{
78-
// TODO:a handle clip (maybe api need to be changed)
76+
_g.IntersectClip(Utils.Convert(rect));
77+
_g.Save();
7978
}
8079

81-
public override void SetClipExclude(RRect rect)
82-
{
83-
// TODO:a handle clip (maybe api need to be changed)
84-
}
80+
public override void PushClipExclude(RRect rect)
81+
{ }
8582

8683
public override Object SetAntiAliasSmoothingMode()
8784
{
@@ -206,10 +203,10 @@ public override void DrawRectangle(RBrush brush, double x, double y, double widt
206203
else
207204
{
208205
_g.DrawRectangle((XBrush)xBrush, x, y, width, height);
209-
206+
210207
// handle bug in PdfSharp that keeps the brush color for next string draw
211-
if(xBrush is XLinearGradientBrush)
212-
_g.DrawRectangle(XBrushes.White, 0,0,0.1,0.1);
208+
if (xBrush is XLinearGradientBrush)
209+
_g.DrawRectangle(XBrushes.White, 0, 0, 0.1, 0.1);
213210
}
214211
}
215212

Source/HtmlRenderer.WPF/Adapters/GraphicsAdapter.cs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ internal sealed class GraphicsAdapter : RGraphics
4545
/// Init.
4646
/// </summary>
4747
/// <param name="g">the WPF graphics object to use</param>
48+
/// <param name="initialClip">the initial clip of the graphics</param>
4849
/// <param name="releaseGraphics">optional: if to release the graphics object on dispose (default - false)</param>
49-
public GraphicsAdapter(DrawingContext g, bool releaseGraphics = false)
50-
: base(WpfAdapter.Instance)
50+
public GraphicsAdapter(DrawingContext g, RRect initialClip, bool releaseGraphics = false)
51+
: base(WpfAdapter.Instance, initialClip)
5152
{
5253
ArgChecker.AssertArgNotNull(g, "g");
5354

@@ -60,42 +61,36 @@ public override RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor
6061
return new BrushAdapter(new LinearGradientBrush(Utils.Convert(color1), Utils.Convert(color2), angle));
6162
}
6263

63-
public override RRect GetClip()
64+
public override void PopClip()
6465
{
65-
// TODO:a handle clip
66-
// var clip = _g.ClipBounds;
67-
// return Utils.Convert(clip);
68-
return new RRect(0, 0, 9999, 9999);
66+
_g.Pop();
67+
_clipStack.Pop();
6968
}
7069

71-
public override void SetClipReplace(RRect rect)
70+
public override void PushClip(RRect rect)
7271
{
73-
// TODO:a handle clip
74-
// _g.SetClip(Utils.Convert(rect), CombineMode.Replace);
72+
_clipStack.Push(rect);
73+
_g.PushClip(new RectangleGeometry(Utils.Convert(rect)));
7574
}
7675

77-
public override void SetClipExclude(RRect rect)
76+
public override void PushClipExclude(RRect rect)
7877
{
79-
// TODO:a handle clip
80-
// _g.SetClip(Utils.Convert(rect), CombineMode.Exclude);
78+
var geometry = new CombinedGeometry();
79+
geometry.Geometry1 = new RectangleGeometry(Utils.Convert(_clipStack.Peek()));
80+
geometry.Geometry2 = new RectangleGeometry(Utils.Convert(rect));
81+
geometry.GeometryCombineMode = GeometryCombineMode.Exclude;
82+
83+
_clipStack.Push(_clipStack.Peek());
84+
_g.PushClip(geometry);
8185
}
8286

8387
public override Object SetAntiAliasSmoothingMode()
8488
{
85-
// var prevMode = _g.SmoothingMode;
86-
// _g.SmoothingMode = SmoothingMode.AntiAlias;
87-
// return prevMode;
8889
return null;
8990
}
9091

9192
public override void ReturnPreviousSmoothingMode(Object prevMode)
92-
{
93-
if (prevMode != null)
94-
{
95-
// TODO:a handle smoothing mode
96-
// _g.SmoothingMode = (SmoothingMode)prevMode;
97-
}
98-
}
93+
{ }
9994

10095
public override RSize MeasureString(string str, RFont font)
10196
{

Source/HtmlRenderer.WPF/HtmlContainer.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,6 @@ public CssData CssData
132132
get { return _htmlContainerInt.CssData; }
133133
}
134134

135-
/// <summary>
136-
/// Gets or sets a value indicating if anti-aliasing should be avoided for geometry like backgrounds and borders (default - false).
137-
/// </summary>
138-
public bool AvoidGeometryAntialias
139-
{
140-
get { return _htmlContainerInt.AvoidGeometryAntialias; }
141-
set { _htmlContainerInt.AvoidGeometryAntialias = value; }
142-
}
143-
144135
/// <summary>
145136
/// Gets or sets a value indicating if image asynchronous loading should be avoided (default - false).<br/>
146137
/// True - images are loaded synchronously during html parsing.<br/>
@@ -334,7 +325,7 @@ public void PerformLayout(DrawingContext g)
334325
{
335326
ArgChecker.AssertArgNotNull(g, "g");
336327

337-
using (var ig = new GraphicsAdapter(g))
328+
using (var ig = new GraphicsAdapter(g, new RRect(0, 0, double.MaxValue, double.MaxValue)))
338329
{
339330
_htmlContainerInt.PerformLayout(ig);
340331
}
@@ -344,11 +335,12 @@ public void PerformLayout(DrawingContext g)
344335
/// Render the html using the given device.
345336
/// </summary>
346337
/// <param name="g">the device to use to render</param>
347-
public void PerformPaint(DrawingContext g)
338+
/// <param name="clip">the clip rectangle of the html container</param>
339+
public void PerformPaint(DrawingContext g, Rect clip)
348340
{
349341
ArgChecker.AssertArgNotNull(g, "g");
350342

351-
using (var ig = new GraphicsAdapter(g))
343+
using (var ig = new GraphicsAdapter(g, Utils.Convert(clip)))
352344
{
353345
_htmlContainerInt.PerformPaint(ig);
354346
}

Source/HtmlRenderer.WPF/HtmlPanel.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,6 @@ public HtmlPanel()
128128
/// </summary>
129129
public event EventHandler<HtmlImageLoadEventArgs> ImageLoad;
130130

131-
/// <summary>
132-
/// Gets or sets a value indicating if anti-aliasing should be avoided for geometry like backgrounds and borders (default - false).
133-
/// </summary>
134-
[Category("Behavior")]
135-
[DefaultValue(false)]
136-
[Description("If anti-aliasing should be avoided for geometry like backgrounds and borders")]
137-
public virtual bool AvoidGeometryAntialias
138-
{
139-
get { return _htmlContainer.AvoidGeometryAntialias; }
140-
set { _htmlContainer.AvoidGeometryAntialias = value; }
141-
}
142-
143131
/// <summary>
144132
/// Gets or sets a value indicating if image loading only when visible should be avoided (default - false).<br/>
145133
/// True - images are loaded as soon as the html is parsed.<br/>

Source/HtmlRenderer.WPF/HtmlRender.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ private static Size MeasureHtmlByRestrictions(HtmlContainer htmlContainer, Size
397397
}
398398
399399
*/
400-
400+
401401
/// <summary>
402402
/// Renders the specified HTML source on the specified location and max size restriction.<br/>
403403
/// If <paramref name="maxSize"/>.Width is zero the html will use all the required width, otherwise it will perform line
@@ -418,19 +418,19 @@ private static Size MeasureHtmlByRestrictions(HtmlContainer htmlContainer, Size
418418
/// <returns>the actual size of the rendered html</returns>
419419
private static Size RenderClip(DrawingContext g, string html, Point location, Size maxSize, CssData cssData, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad, EventHandler<HtmlImageLoadEventArgs> imageLoad)
420420
{
421-
// Region prevClip = null;
422-
// if (maxSize.Height > 0)
423-
// {
424-
// prevClip = g.Clip;
425-
// g.SetClip(new RectangleF(location, maxSize));
426-
// }
421+
// Region prevClip = null;
422+
// if (maxSize.Height > 0)
423+
// {
424+
// prevClip = g.Clip;
425+
// g.SetClip(new RectangleF(location, maxSize));
426+
// }
427427

428428
var actualSize = RenderHtml(g, html, location, maxSize, cssData, stylesheetLoad, imageLoad);
429429

430-
// if (prevClip != null)
431-
// {
432-
// g.SetClip(prevClip, CombineMode.Replace);
433-
// }
430+
// if (prevClip != null)
431+
// {
432+
// g.SetClip(prevClip, CombineMode.Replace);
433+
// }
434434

435435
return actualSize;
436436
}
@@ -471,7 +471,7 @@ private static Size RenderHtml(DrawingContext g, string html, Point location, Si
471471

472472
container.SetHtml(html, cssData);
473473
container.PerformLayout(g);
474-
container.PerformPaint(g);
474+
container.PerformPaint(g, new Rect(0, 0, double.MaxValue, double.MaxValue));
475475

476476
actualSize = container.ActualSize;
477477
}

Source/HtmlRenderer.WPF/HtmlUIElement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ protected override void OnRender(DrawingContext context)
8686
{
8787
if (_htmlContainer != null)
8888
{
89-
_htmlContainer.PerformPaint(context);
89+
_htmlContainer.PerformPaint(context, new Rect(RenderSize));
9090

9191
// TODO:a handle if we need to refresh the pointer here
9292
// call mouse move to handle paint after scroll or html change affecting mouse cursor.
9393
// var mp = PointToClient(MousePosition);
9494
// _htmlContainer.HandleMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, mp.X, mp.Y, 0));
9595
}
9696
}
97-
97+
9898
}
9999
}

Source/HtmlRenderer.WinForms/Adapters/GraphicsAdapter.cs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ internal sealed class GraphicsAdapter : RGraphics
2828
#region Fields and Consts
2929

3030
/// <summary>
31-
/// used for <see cref="MeasureString(string,RFont,double,out int,out int)"/> calculation.
31+
/// used for <see cref="MeasureString(string,RFont,double,out int,out double)"/> calculation.
3232
/// </summary>
3333
private static readonly int[] _charFit = new int[1];
3434

3535
/// <summary>
36-
/// used for <see cref="MeasureString(string,RFont,double,out int,out int)"/> calculation.
36+
/// used for <see cref="MeasureString(string,RFont,double,out int,out double)"/> calculation.
3737
/// </summary>
3838
private static readonly int[] _charFitWidth = new int[1000];
3939

@@ -98,7 +98,7 @@ static GraphicsAdapter()
9898
/// <param name="useGdiPlusTextRendering">Use GDI+ text rendering to measure/draw text</param>
9999
/// <param name="releaseGraphics">optional: if to release the graphics object on dispose (default - false)</param>
100100
public GraphicsAdapter(Graphics g, bool useGdiPlusTextRendering, bool releaseGraphics = false)
101-
: base(WinFormsAdapter.Instance)
101+
: base(WinFormsAdapter.Instance, Utils.Convert(g.ClipBounds))
102102
{
103103
ArgChecker.AssertArgNotNull(g, "g");
104104

@@ -112,31 +112,24 @@ public override RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor
112112
return new BrushAdapter(new LinearGradientBrush(Utils.Convert(rect), Utils.Convert(color1), Utils.Convert(color2), (float)angle), true);
113113
}
114114

115-
public override RRect GetClip()
115+
public override void PopClip()
116116
{
117-
RectangleF clip;
118-
if (_hdc == IntPtr.Zero)
119-
{
120-
clip = _g.ClipBounds;
121-
}
122-
else
123-
{
124-
Rectangle lprc;
125-
Win32Utils.GetClipBox(_hdc, out lprc);
126-
clip = lprc;
127-
}
128-
return Utils.Convert(clip);
117+
ReleaseHdc();
118+
_clipStack.Pop();
119+
_g.SetClip(Utils.Convert(_clipStack.Peek()), CombineMode.Replace);
129120
}
130121

131-
public override void SetClipReplace(RRect rect)
122+
public override void PushClip(RRect rect)
132123
{
133124
ReleaseHdc();
125+
_clipStack.Push(rect);
134126
_g.SetClip(Utils.Convert(rect), CombineMode.Replace);
135127
}
136128

137-
public override void SetClipExclude(RRect rect)
129+
public override void PushClipExclude(RRect rect)
138130
{
139131
ReleaseHdc();
132+
_clipStack.Push(_clipStack.Peek());
140133
_g.SetClip(Utils.Convert(rect), CombineMode.Exclude);
141134
}
142135

Source/HtmlRenderer/Adapters/RGraphics.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// "The Art of War"
1212

1313
using System;
14+
using System.Collections.Generic;
1415
using HtmlRenderer.Adapters.Entities;
1516
using HtmlRenderer.Core.Utils;
1617

@@ -30,17 +31,23 @@ public abstract class RGraphics : IDisposable
3031
/// </summary>
3132
protected readonly Adapter _adapter;
3233

34+
/// <summary>
35+
/// Te clipping bound stack as clips are pushed/poped to/from the graphics
36+
/// </summary>
37+
protected readonly Stack<RRect> _clipStack = new Stack<RRect>();
38+
3339
#endregion
3440

3541

3642
/// <summary>
3743
/// Init.
3844
/// </summary>
39-
protected RGraphics(Adapter adapter)
45+
protected RGraphics(Adapter adapter, RRect initialClip)
4046
{
4147
ArgChecker.AssertArgNotNull(adapter, "global");
4248

4349
_adapter = adapter;
50+
_clipStack.Push(initialClip);
4451
}
4552

4653
/// <summary>
@@ -77,19 +84,27 @@ public virtual RBrush GetSolidBrush(RColor color)
7784
/// Gets a Rectangle structure that bounds the clipping region of this Graphics.
7885
/// </summary>
7986
/// <returns>A rectangle structure that represents a bounding rectangle for the clipping region of this Graphics.</returns>
80-
public abstract RRect GetClip();
87+
public RRect GetClip()
88+
{
89+
return _clipStack.Peek();
90+
}
91+
92+
/// <summary>
93+
/// Pop the latest clip push.
94+
/// </summary>
95+
public abstract void PopClip();
8196

8297
/// <summary>
83-
/// Sets the clipping region of this Graphics to the result of the specified operation combining the current clip region and the rectangle specified by a Rectangle structure.
98+
/// Push the clipping region of this Graphics to interception of current clipping rectangle and the given rectangle.
8499
/// </summary>
85-
/// <param name="rect">Rectangle structure to combine.</param>
86-
public abstract void SetClipReplace(RRect rect);
100+
/// <param name="rect">Rectangle to clip to.</param>
101+
public abstract void PushClip(RRect rect);
87102

88103
/// <summary>
89-
/// Sets the clipping region of this Graphics to the result of the specified operation combining the current clip region and the rectangle specified by a Rectangle structure.
104+
/// Push the clipping region of this Graphics to exclude the given rectangle from the current clipping rectangle.
90105
/// </summary>
91-
/// <param name="rect">Rectangle structure to combine.</param>
92-
public abstract void SetClipExclude(RRect rect);
106+
/// <param name="rect">Rectangle to exclude clipping in.</param>
107+
public abstract void PushClipExclude(RRect rect);
93108

94109
/// <summary>
95110
/// Set the graphics smooth mode to use anti-alias.<br/>

0 commit comments

Comments
 (0)