Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions Source/Demo/Common/DemoUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ public static string GetStylesheet(string src)
a:link { text-decoration: none; }
a:hover { text-decoration: underline; }
.gray { color:gray; }
.example { background-color:#efefef; corner-radius:5px; padding:0.5em; }
.whitehole { background-color:white; corner-radius:10px; padding:15px; }
.example { background-color:#efefef; border-radius:5px; padding:0.5em; }
.whitehole { background-color:white; border-radius:10px; padding:15px; }
.caption { font-size: 1.1em }
.comment { color: green; margin-bottom: 5px; margin-left: 3px; }
.comment2 { color: green; }";
Expand Down
2 changes: 1 addition & 1 deletion Source/Demo/Common/Samples/00.Intro.htm
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<title>Intro</title>
<link rel="Stylesheet" href="StyleSheet" />
</head>
<body style="background-color: #333; background-gradient: #707; background-gradient-angle: 60; margin: 0;">
<body style="background-image: linear-gradient(60deg, #333, #707); margin: 0;">
<h1 align="center" style="color: white">
HTML Renderer Project - $$Platform$$
<br />
Expand Down
81 changes: 36 additions & 45 deletions Source/Demo/Common/Samples/07.Additional features.htm
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@
<style>
<!--
.g1, .g2, .g3, .g4, .g5 {
background-color: red;
background-gradient: yellow;
padding: 22px;
}

.g1 { background-gradient-angle: 0; }
.g1 { background-image: linear-gradient(0deg, red, yellow); }

.g2 { background-gradient-angle: 45; }
.g2 { background-image: linear-gradient(45deg, red, yellow); }

.g3 { background-gradient-angle: 90; }
.g3 { background-image: linear-gradient(90deg, red, yellow); }

.g4 { background-gradient-angle: 135; }
.g4 { background-image: linear-gradient(135deg, red, yellow); }

.g5 { background-gradient-angle: 180; }
.g5 { background-image: linear-gradient(180deg, red, yellow); }

.c1, .c2, .c3, .c4, .c5 {
background-color: olive;
Expand All @@ -27,16 +25,16 @@
vertical-align: middle;
}

.c1 { corner-radius: 0px; }
.c1 { border-radius: 0px; }

.c2 { corner-radius: 10px; }
.c2 { border-radius: 10px; }

.c3 { corner-radius: 0px 10px 10px 0px; }
.c3 { border-radius: 0px 10px 10px 0px; }

.c4 { corner-radius: 18px; }
.c4 { border-radius: 18px; }

.c5 {
corner-radius: 10px;
border-radius: 10px;
border: outset #BBBB00 2px;
}

Expand All @@ -59,24 +57,17 @@ <h1>
<h2>
Graphic features</h2>
<p>
I have always wanted the W3C to add this features to the CSS spec (and so far, not
there yet :)</p>
Standard CSS backgrounds and border radii, same as any modern browser.</p>
<ul>
<li><b>Gradients on backgrounds</b></li>
<li><b>Rounded corners</b></li>
</ul>
<p>
And I think many many web designers would agree. Is it so hard or what?.</p>
<h3>
Background Gradients</h3>
<p>
It is a simple two color linear gradient, achieved by the adding of two CSS properties:</p>
<ol>
<li><code>background-gradient: (#Color)</code> - Second color of the gradient background,
the first one is given by <code>background-color</code>. Not inherited.</li>
<li><code>background-gradient-angle: (number)</code> - Angle (in degrees, clockwise) of
the gradient. Not inherited. Initial value:90</li>
</ol>
A <code>background-image</code> can be a <code>linear-gradient()</code> (or
<code>repeating-linear-gradient()</code>) function: an angle or <code>to &lt;side&gt;</code>
direction, followed by two or more comma-separated color stops.</p>
<b>Some examples</b>
<!-- Gradients table -->
<table width="300px">
Expand All @@ -94,19 +85,19 @@ <h3>
</tr>
<tr>
<td>
0 degrees
0deg
</td>
<td>
45 degrees
45deg
</td>
<td>
90 degrees
90deg
</td>
<td>
135 degrees
135deg
</td>
<td>
180 degrees
180deg
</td>
</tr>
</table>
Expand All @@ -119,18 +110,18 @@ <h3>
website you visit nowadays makes use of rounded corners, where a not very nice trick
with images and tables must be used.</p>
<p>
In this renderer, the rounded corners are achieved by adding this CSS properties:</p>
In this renderer, the rounded corners are achieved with the standard CSS properties:</p>
<ul>
<li><code>corner-ne-radius: (length)</code> Indicates the radius of the north-east corner.
Not ineritted</li>
<li><code>corner-se-radius: (length)</code> Indicates the radius of the south-east corner.
Not ineritted</li>
<li><code>corner-sw-radius: (length)</code> Indicates the radius of the south-west corner.
Not ineritted</li>
<li><code>corner-nw-radius: (length)</code> Indicates the radius of the north-west corner.
Not ineritted</li>
<li><code>corner-radius: (length){1,4}</code> Shorthand for the other corner properties.
Not ineritted</li>
<li><code>border-top-left-radius: (length){1,2}</code> Indicates the radius of the top-left
corner. Not inherited</li>
<li><code>border-top-right-radius: (length){1,2}</code> Indicates the radius of the top-right
corner. Not inherited</li>
<li><code>border-bottom-right-radius: (length){1,2}</code> Indicates the radius of the bottom-right
corner. Not inherited</li>
<li><code>border-bottom-left-radius: (length){1,2}</code> Indicates the radius of the bottom-left
corner. Not inherited</li>
<li><code>border-radius: (length){1,4} [ / (length){1,4} ]?</code> Shorthand for the other
corner properties, with an optional "/" for elliptical corners. Not inherited</li>
</ul>
<!-- Corners table -->
<b>Some examples</b>
Expand Down Expand Up @@ -160,11 +151,11 @@ <h3>
</tr>
</table>
<pre>.c1, .c2, .c3, .c4, .c5 { background-color:olive; border:0px; color:white; vertical-align:middle; }
.c1 { corner-radius: 0px }
.c2 { corner-radius: 10px }
.c3 { corner-radius: 0px 10px 10px 0px }
.c4 { corner-radius: 18px }
.c5 { corner-radius: 10px; border: outset #bb0 2px; }</pre>
.c1 { border-radius: 0px }
.c2 { border-radius: 10px }
.c3 { border-radius: 0px 10px 10px 0px }
.c4 { border-radius: 18px }
.c5 { border-radius: 10px; border: outset #bb0 2px; }</pre>
</blockquote>
</body>
</html>
</html>
5 changes: 2 additions & 3 deletions Source/Demo/Common/Samples/08.Tooltip.htm
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ <h2>Default tooltip style
<pre>
.htmltooltip {
border:solid 1px #767676;
background-color:white;
background-gradient:#E4E5F0;
padding: 8px;
background-color:#E4E5F0;
padding: 8px;
Font: 9pt Tahoma;
}</pre>
<h2>Examples
Expand Down
16 changes: 8 additions & 8 deletions Source/Demo/Common/TestSamples/12.Text.htm
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
<head>
<title>Text</title>
<link rel="Stylesheet" href="StyleSheet" />
<style>
.right {
text-align: right;
border-width: 1px;
border-style: solid;
border-color: blue;
}
<style>
.right {
text-align: right;
border-width: 1px;
border-style: solid;
border-color: blue;
}
</style>
</head>
<body>
Expand Down Expand Up @@ -54,7 +54,7 @@ <h2>Transparent text</h2>
elementum dolor ac mauris. Ut tristique. In varius volutpat metus. Integer leo dolor, tristique a, dignissim ac, iaculis eget, elit. Donec arcu.
</div>
</p>
<p style="background-color: #a33; background-gradient: rgb(255, 215, 0); background-gradient-angle: 0">
<p style="background-image: linear-gradient(to right, #a33, rgb(255, 215, 0))">
<div style="color: rgba(0, 255, 0, 140)">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ornare mollis elit. Integer_sagittis_Fusce_elementum_commodo_felis_Vivamus_lacinia_eleifend_libero_Donec
lacus.
Expand Down
12 changes: 6 additions & 6 deletions Source/Demo/Common/TestSamples/16.Borders.htm
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
</div>
</p>
<p>
<div style="padding: 5px; border: 1px solid black; corner-radius: 5px;">
border 1px with corner-radius 5px
<div style="padding: 5px; border: 1px solid black; border-radius: 5px;">
border 1px with border-radius 5px
</div>
</p>
<p>
<div style="padding: 5px; border: 2px solid black; corner-radius: 10px;">
border 2px with corner-radius 10px
<div style="padding: 5px; border: 2px solid black; border-radius: 10px;">
border 2px with border-radius 10px
</div>
</p>
<p>
Expand All @@ -37,8 +37,8 @@
</div>
</p>
<p>
<div style="padding: 5px; border: 2px dashed darkred; corner-radius: 10px;">
dashed border 2px with corner-radius 10px
<div style="padding: 5px; border: 2px dashed darkred; border-radius: 10px;">
dashed border 2px with border-radius 10px
</div>
</p>
</div>
Expand Down
46 changes: 46 additions & 0 deletions Source/HtmlRenderer.PdfSharp/Adapters/GradientBrushAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they begin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
//
// - Sun Tsu,
// "The Art of War"

using TheArtOfDev.HtmlRenderer.Adapters;
using TheArtOfDev.HtmlRenderer.Adapters.Entities;

namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters
{
/// <summary>
/// A multi-stop linear gradient "brush" for the PdfSharp backend. Unlike <see cref="BrushAdapter"/>,
/// this does not wrap a real <c>PdfSharp.Drawing.XBrush</c> - <c>XLinearGradientBrush</c> in the
/// PDFsharp 1.50 package this project depends on only supports 2 colors, no stop list. Instead this
/// just carries the gradient line and stops; <see cref="GraphicsAdapter"/>'s <c>DrawPath</c>/
/// <c>DrawRectangle</c> special-case this type and paint it as a series of adjacent 2-color
/// <c>XLinearGradientBrush</c> bands, one per consecutive stop pair - each band is a real 2-color
/// linear gradient by definition, so the composite is an exact piecewise-linear rendering, not an
/// approximation.
/// </summary>
internal sealed class GradientBrushAdapter : RBrush
{
public GradientBrushAdapter(RPoint p1, RPoint p2, (RColor Color, double Position)[] stops)
{
P1 = p1;
P2 = p2;
Stops = stops;
}

public RPoint P1 { get; }

public RPoint P2 { get; }

public (RColor Color, double Position)[] Stops { get; }

public override void Dispose()
{ }
}
}
72 changes: 72 additions & 0 deletions Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ public override void DrawRectangle(RPen pen, double x, double y, double width, d

public override void DrawRectangle(RBrush brush, double x, double y, double width, double height)
{
if (brush is GradientBrushAdapter gradient)
{
var rectPath = new XGraphicsPath();
rectPath.AddRectangle(x, y, width, height);
FillGradient(gradient, rectPath);
return;
}

var xBrush = ((BrushAdapter)brush).Brush;
var xTextureBrush = xBrush as XTextureBrush;
if (xTextureBrush != null)
Expand Down Expand Up @@ -188,6 +196,12 @@ public override void DrawPath(RPen pen, RGraphicsPath path)

public override void DrawPath(RBrush brush, RGraphicsPath path)
{
if (brush is GradientBrushAdapter gradient)
{
FillGradient(gradient, ((GraphicsPathAdapter)path).GraphicsPath);
return;
}

_g.DrawPath((XBrush)((BrushAdapter)brush).Brush, ((GraphicsPathAdapter)path).GraphicsPath);
}

Expand All @@ -199,6 +213,64 @@ public override void DrawPolygon(RBrush brush, RPoint[] points)
}
}

/// <summary>
/// Paints a multi-stop linear gradient by clipping to <paramref name="targetPath"/> and drawing
/// one real 2-color <see cref="XLinearGradientBrush"/> band per consecutive stop pair, each
/// spanning the full perpendicular extent needed to cover the target - see
/// <see cref="GradientBrushAdapter"/> for why this backend needs banding instead of a single brush.
/// </summary>
private void FillGradient(GradientBrushAdapter gradient, XGraphicsPath targetPath)
{
var stops = gradient.Stops;
if (stops.Length == 0)
return;

_g.Save();
_g.IntersectClip(targetPath);

double dx = gradient.P2.X - gradient.P1.X;
double dy = gradient.P2.Y - gradient.P1.Y;
double len = Math.Sqrt(dx * dx + dy * dy);

if (stops.Length == 1 || len < 1e-6)
{
// Degenerate gradient line (single stop, or a zero-size box) - just flat-fill with the
// last color, matching what a real linear gradient converges to in that case.
var flatBrush = new XSolidBrush(Utils.Convert(stops[stops.Length - 1].Color));
_g.DrawRectangle(flatBrush, -1e5, -1e5, 2e5, 2e5);
_g.Restore();
_g.DrawRectangle(XBrushes.White, 0, 0, 0.1, 0.1);
return;
}

double ux = dx / len, uy = dy / len;
double perpX = -uy, perpY = ux;
double perpHalf = Math.Max(len, 1.0) * 4.0;

for (int i = 0; i < stops.Length - 1; i++)
{
double t1 = stops[i].Position, t2 = stops[i + 1].Position;
var bp1 = new XPoint(gradient.P1.X + ux * len * t1, gradient.P1.Y + uy * len * t1);
var bp2 = new XPoint(gradient.P1.X + ux * len * t2, gradient.P1.Y + uy * len * t2);

var band = new[]
{
new XPoint(bp1.X - perpX * perpHalf, bp1.Y - perpY * perpHalf),
new XPoint(bp1.X + perpX * perpHalf, bp1.Y + perpY * perpHalf),
new XPoint(bp2.X + perpX * perpHalf, bp2.Y + perpY * perpHalf),
new XPoint(bp2.X - perpX * perpHalf, bp2.Y - perpY * perpHalf),
};

var bandBrush = new XLinearGradientBrush(bp1, bp2, Utils.Convert(stops[i].Color), Utils.Convert(stops[i + 1].Color));
_g.DrawPolygon(bandBrush, band, XFillMode.Winding);
}

_g.Restore();

// handle bug in PdfSharp that keeps the brush color for next string draw
_g.DrawRectangle(XBrushes.White, 0, 0, 0.1, 0.1);
}

#endregion
}
}
8 changes: 4 additions & 4 deletions Source/HtmlRenderer.PdfSharp/Adapters/GraphicsPathAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ public override void LineTo(double x, double y)
_lastPoint = new RPoint(x, y);
}

public override void ArcTo(double x, double y, double size, Corner corner)
public override void ArcTo(double x, double y, double radiusX, double radiusY, Corner corner)
{
float left = (float)(Math.Min(x, _lastPoint.X) - (corner == Corner.TopRight || corner == Corner.BottomRight ? size : 0));
float top = (float)(Math.Min(y, _lastPoint.Y) - (corner == Corner.BottomLeft || corner == Corner.BottomRight ? size : 0));
_graphicsPath.AddArc(left, top, (float)size * 2, (float)size * 2, GetStartAngle(corner), 90);
float left = (float)(Math.Min(x, _lastPoint.X) - (corner == Corner.TopRight || corner == Corner.BottomRight ? radiusX : 0));
float top = (float)(Math.Min(y, _lastPoint.Y) - (corner == Corner.BottomLeft || corner == Corner.BottomRight ? radiusY : 0));
_graphicsPath.AddArc(left, top, (float)radiusX * 2, (float)radiusY * 2, GetStartAngle(corner), 90);
_lastPoint = new RPoint(x, y);
}

Expand Down
Loading