зеркало из https://github.com/microsoft/Win2D.git
CanvasControl.ClearColor property
This gives control over the color that the CanvasControl is cleared to before the Draw event is raised.
This commit is contained in:
Родитель
460b22abd2
Коммит
beba8c5df4
|
@ -21,17 +21,13 @@ To give you a flavor of what the code looks like, here is a snippet of XAML:
|
|||
xmlns:canvas="using:Microsoft.Graphics.Canvas"
|
||||
|
||||
<Grid>
|
||||
<canvas:CanvasControl x:Name="canvasControl" />
|
||||
<canvas:CanvasControl x:Name="canvasControl" Draw="canvasControl_Draw" ClearColor="CornflowerBlue" />
|
||||
</Grid>
|
||||
```
|
||||
and C#:
|
||||
```cs
|
||||
canvasControl.Draw += canvasControl_Draw;
|
||||
```
|
||||
```cs
|
||||
void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawEllipse(155, 115, 80, 30, Colors.Black, 3);
|
||||
args.DrawingSession.DrawText("Hello, world!", 100, 100, Colors.Yellow);
|
||||
}
|
||||
|
|
|
@ -54,8 +54,6 @@ namespace ExampleGallery
|
|||
{
|
||||
var ds = args.DrawingSession;
|
||||
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
// If the window size has changed, (re)create the text bitmap.
|
||||
var newCanvasSize = new Size(sender.ActualWidth, sender.ActualHeight);
|
||||
if (oldCanvasSize != newCanvasSize)
|
||||
|
|
|
@ -55,8 +55,6 @@ namespace ExampleGallery
|
|||
|
||||
private void DrawCanvasState(CanvasControl canvas, CanvasDrawingSession ds, int drawCount)
|
||||
{
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
ds.DrawLine(0, 0, (float)canvas.ActualWidth, (float)canvas.ActualHeight, Colors.Aqua);
|
||||
ds.DrawLine(0, (float)canvas.ActualHeight, (float)canvas.ActualWidth, 0, Colors.Aqua);
|
||||
|
||||
|
|
|
@ -82,7 +82,6 @@ namespace ExampleGallery
|
|||
private void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
var ds = args.DrawingSession;
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
if (!isLoaded)
|
||||
return;
|
||||
|
@ -758,7 +757,7 @@ namespace ExampleGallery
|
|||
|
||||
using (var ds = renderTarget.CreateDrawingSession())
|
||||
{
|
||||
ds.Clear(Colors.Transparent);
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
ds.DrawText("This text is drawn onto a rendertarget", 10, 10, Colors.White);
|
||||
ds.DrawText("with a different color per line,", 10, 40, Colors.Red);
|
||||
|
@ -850,7 +849,7 @@ namespace ExampleGallery
|
|||
|
||||
using (var ds = textOverlay.CreateDrawingSession())
|
||||
{
|
||||
ds.Clear(Colors.Transparent);
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
ds.DrawText(effect.GetType().Name.Replace("Effect", ""), 0, 0, Colors.White);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,8 +81,6 @@ namespace ExampleGallery
|
|||
}
|
||||
}
|
||||
|
||||
args.DrawingSession.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
// Display the current surface.
|
||||
invertEffect.Source = currentSurface;
|
||||
transformEffect.TransformMatrix = GetDisplayTransform();
|
||||
|
|
|
@ -61,7 +61,6 @@ namespace ExampleGallery
|
|||
void Canvas_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
var ds = args.DrawingSession;
|
||||
ds.Clear(Color.FromArgb(0,0,0,0));
|
||||
|
||||
var shape = this.Shapes.SelectedItem as Shape;
|
||||
if (shape == null)
|
||||
|
|
|
@ -62,8 +62,6 @@ namespace ExampleGallery
|
|||
|
||||
var ds = args.DrawingSession;
|
||||
|
||||
ds.Clear(Color.FromArgb(0, 0, 0, 0));
|
||||
|
||||
var width = (float)sender.ActualWidth;
|
||||
var height = (float)sender.ActualHeight;
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
|
||||
if (isLoaded)
|
||||
{
|
||||
args.DrawingSession.DrawImage(cat, new Point(42, 42));
|
||||
|
|
|
@ -34,7 +34,7 @@ under the License.
|
|||
<p>Add a CanvasControl to the page:</p>
|
||||
<code>
|
||||
<Grid>
|
||||
<canvas:CanvasControl x:Name="myWidget"/>
|
||||
<canvas:CanvasControl x:Name="myWidget" CreateResources="myWidget_CreateResources" Draw="myWidget_Draw" ClearColor="CornFlowerBlue"/>
|
||||
</Grid>
|
||||
</code>
|
||||
<p>Edit MainPage.xaml.cs, and add some drawing code:</p>
|
||||
|
@ -46,9 +46,6 @@ under the License.
|
|||
public MainPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
myWidget.CreateResources += myWidget_CreateResources;
|
||||
myWidget.Draw += myWidget_Draw;
|
||||
}
|
||||
|
||||
void myWidget_CreateResources(CanvasControl sender, object args)
|
||||
|
@ -59,7 +56,6 @@ under the License.
|
|||
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawEllipse(155, 115, 80, 30, Colors.Black, 3);
|
||||
args.DrawingSession.DrawText("Hello, world!", 100, 100, Colors.Yellow);
|
||||
}
|
||||
|
@ -106,6 +102,18 @@ under the License.
|
|||
so you can draw different things each time.</p>
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="P:Microsoft.Graphics.Canvas.CanvasControl.ClearColor">
|
||||
<summary>The color that the control is cleared to before the Draw event is raised.</summary>
|
||||
<remarks>
|
||||
<p>
|
||||
ClearColor defaults to transparent black, that is Color.FromArgb(0,0,0,0).
|
||||
</p>
|
||||
<p>
|
||||
Modifying ClearColor will cause the control to redraw, as if
|
||||
Invalidate() was called.
|
||||
</p>
|
||||
</remarks>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="T:Microsoft.Graphics.Canvas.CanvasDrawEventArgs">
|
||||
|
@ -118,6 +126,5 @@ under the License.
|
|||
<summary>Gets the drawing session for use by the current event handler.
|
||||
This provides methods to draw lines, rectangles, text etc.</summary>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
</doc>
|
||||
|
|
|
@ -37,7 +37,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawImage(blendEffect, new Point(42, 42));
|
||||
}
|
||||
</code>
|
||||
|
|
|
@ -34,7 +34,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawImage(compositeEffect, new Point(42, 42));
|
||||
}
|
||||
</code>
|
||||
|
|
|
@ -35,7 +35,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawImage(blurEffect, new Point(42, 42));
|
||||
}
|
||||
</code>
|
||||
|
|
|
@ -35,7 +35,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawImage(saturationEffect, new Point(42, 42));
|
||||
}
|
||||
</code>
|
||||
|
|
|
@ -35,7 +35,6 @@ under the License.
|
|||
<code>
|
||||
void myWidget_Draw(CanvasControl sender, CanvasDrawEventArgs args)
|
||||
{
|
||||
args.DrawingSession.Clear(Colors.CornflowerBlue);
|
||||
args.DrawingSession.DrawImage(transformEffect, new Point(42, 42));
|
||||
}
|
||||
</code>
|
||||
|
|
|
@ -53,6 +53,14 @@ namespace Microsoft.Graphics.Canvas
|
|||
|
||||
[eventremove] HRESULT Draw([in] EventRegistrationToken token);
|
||||
|
||||
//
|
||||
// Before the Draw event is raised, the control is cleared to
|
||||
// ClearColor. ClearColor defaults to transparent black (0,0,0,0).
|
||||
// Setting ClearColor to a different value triggers a Draw.
|
||||
//
|
||||
[propput] HRESULT ClearColor([in] Windows.UI.Color value);
|
||||
[propget] HRESULT ClearColor([out, retval] Windows.UI.Color* value);
|
||||
|
||||
HRESULT Invalidate();
|
||||
}
|
||||
|
||||
|
|
|
@ -183,16 +183,17 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
handler);
|
||||
}
|
||||
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height) override
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height, CanvasBackground backgroundMode) override
|
||||
{
|
||||
ComPtr<ICanvasResourceCreator> resourceCreator;
|
||||
ThrowIfFailed(device->QueryInterface(resourceCreator.GetAddressOf()));
|
||||
|
||||
ComPtr<ICanvasImageSource> imageSource;
|
||||
ThrowIfFailed(m_canvasImageSourceFactory->Create(
|
||||
ThrowIfFailed(m_canvasImageSourceFactory->CreateWithBackground(
|
||||
resourceCreator.Get(),
|
||||
width,
|
||||
height,
|
||||
height,
|
||||
backgroundMode,
|
||||
&imageSource));
|
||||
|
||||
// Since we know that CanvasImageSourceFactory will only ever return
|
||||
|
@ -298,6 +299,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
, m_needToHookCompositionRendering(false)
|
||||
, m_imageSourceNeedsReset(false)
|
||||
, m_isLoaded(false)
|
||||
, m_clearColor{}
|
||||
, m_currentWidth(0)
|
||||
, m_currentHeight(0)
|
||||
{
|
||||
|
@ -446,7 +448,8 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
m_canvasImageSource = m_adapter->CreateCanvasImageSource(
|
||||
m_canvasDevice.Get(),
|
||||
width,
|
||||
height);
|
||||
height,
|
||||
m_clearColor.A == 255 ? CanvasBackground::Opaque : CanvasBackground::Transparent);
|
||||
|
||||
m_currentWidth = width;
|
||||
m_currentHeight = height;
|
||||
|
@ -471,7 +474,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
return;
|
||||
}
|
||||
|
||||
auto drawingSession = m_canvasImageSource->CreateDrawingSessionWithDpi(Color{}, m_adapter->GetLogicalDpi());
|
||||
auto drawingSession = m_canvasImageSource->CreateDrawingSessionWithDpi(m_clearColor, m_adapter->GetLogicalDpi());
|
||||
ComPtr<CanvasDrawEventArgs> drawEventArgs = Make<CanvasDrawEventArgs>(drawingSession.Get());
|
||||
CheckMakeResult(drawEventArgs);
|
||||
|
||||
|
@ -591,6 +594,41 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
});
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CanvasControl::put_ClearColor(Color value)
|
||||
{
|
||||
return ExceptionBoundary(
|
||||
[&]
|
||||
{
|
||||
if (m_clearColor.A == value.A &&
|
||||
m_clearColor.R == value.R &&
|
||||
m_clearColor.G == value.G &&
|
||||
m_clearColor.B == value.B)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasOpaque = (m_clearColor.A == 255);
|
||||
bool isOpaque = (value.A == 255);
|
||||
|
||||
auto invalidateReason = InvalidateReason::Default;
|
||||
if (wasOpaque != isOpaque)
|
||||
invalidateReason = InvalidateReason::ImageSourceNeedsReset;
|
||||
|
||||
m_clearColor = value;
|
||||
InvalidateImpl(invalidateReason);
|
||||
});
|
||||
}
|
||||
|
||||
IFACEMETHODIMP CanvasControl::get_ClearColor(Color* value)
|
||||
{
|
||||
return ExceptionBoundary(
|
||||
[&]
|
||||
{
|
||||
CheckInPointer(value);
|
||||
*value = m_clearColor;
|
||||
});
|
||||
}
|
||||
|
||||
HRESULT CanvasControl::OnCompositionRendering(IInspectable*, IInspectable*)
|
||||
{
|
||||
return ExceptionBoundary(
|
||||
|
@ -611,8 +649,20 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
bool CanvasControl::IsWindowVisible()
|
||||
{
|
||||
boolean visible;
|
||||
ThrowIfFailed(m_window->get_Visible(&visible));
|
||||
return !!visible;
|
||||
|
||||
HRESULT hr = m_window->get_Visible(&visible);
|
||||
|
||||
if (hr == E_FAIL)
|
||||
{
|
||||
// In design mode get_Visible will return E_FAIL. In this case we
|
||||
// just treat the window as visible.
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowIfFailed(hr);
|
||||
return !!visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -630,7 +680,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(m_drawLock);
|
||||
|
||||
if (reason == InvalidateReason::SurfaceContentsLost)
|
||||
if (reason == InvalidateReason::ImageSourceNeedsReset)
|
||||
m_imageSourceNeedsReset = true;
|
||||
|
||||
if (m_renderingEventRegistration)
|
||||
|
@ -734,7 +784,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
return ExceptionBoundary(
|
||||
[&]
|
||||
{
|
||||
InvalidateImpl(InvalidateReason::SurfaceContentsLost);
|
||||
InvalidateImpl(InvalidateReason::ImageSourceNeedsReset);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
virtual RegisteredEvent AddCompositionRenderingCallback(IEventHandler<IInspectable*>*) = 0;
|
||||
virtual RegisteredEvent AddSurfaceContentsLostCallback(IEventHandler<IInspectable*>*) = 0;
|
||||
virtual RegisteredEvent AddVisibilityChangedCallback(IWindowVisibilityChangedEventHandler*, IWindow*) = 0;
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height) = 0;
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height, CanvasBackground backgroundMode) = 0;
|
||||
virtual ComPtr<IImage> CreateImageControl() = 0;
|
||||
virtual float GetLogicalDpi() = 0;
|
||||
|
||||
|
@ -133,6 +133,8 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
bool m_imageSourceNeedsReset;
|
||||
bool m_isLoaded;
|
||||
|
||||
Color m_clearColor;
|
||||
|
||||
int m_currentWidth;
|
||||
int m_currentHeight;
|
||||
|
||||
|
@ -160,6 +162,10 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
IFACEMETHODIMP remove_Draw(
|
||||
EventRegistrationToken token);
|
||||
|
||||
IFACEMETHODIMP put_ClearColor(Color value);
|
||||
|
||||
IFACEMETHODIMP get_ClearColor(Color* value);
|
||||
|
||||
//
|
||||
// ICanvasResourceCreator
|
||||
//
|
||||
|
@ -202,7 +208,7 @@ namespace ABI { namespace Microsoft { namespace Graphics { namespace Canvas
|
|||
enum class InvalidateReason
|
||||
{
|
||||
Default,
|
||||
SurfaceContentsLost
|
||||
ImageSourceNeedsReset
|
||||
};
|
||||
|
||||
void InvalidateImpl(InvalidateReason reason = InvalidateReason::Default);
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
ComPtr<MockEventSourceUntyped> CompositionRenderingEventSource;
|
||||
ComPtr<MockEventSourceUntyped> SurfaceContentsLostEventSource;
|
||||
ComPtr<MockEventSource<IEventHandler<SuspendingEventArgs*>>> SuspendingEventSource;
|
||||
CALL_COUNTER(CreateCanvasImageSourceMethod);
|
||||
CALL_COUNTER_WITH_MOCK(CreateCanvasImageSourceMethod, ComPtr<CanvasImageSource>(ICanvasDevice*, int, int, CanvasBackground));
|
||||
|
||||
CanvasControlTestAdapter()
|
||||
: m_mockWindow(Make<MockWindow>())
|
||||
|
@ -83,9 +83,15 @@ public:
|
|||
ThrowIfFailed(SurfaceContentsLostEventSource->InvokeAll(sender, arg));
|
||||
}
|
||||
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height) override
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(
|
||||
ICanvasDevice* device,
|
||||
int width,
|
||||
int height,
|
||||
CanvasBackground backgroundMode) override
|
||||
{
|
||||
CreateCanvasImageSourceMethod.WasCalled();
|
||||
auto result = CreateCanvasImageSourceMethod.WasCalled(device, width, height, backgroundMode);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
auto sisFactory = Make<MockSurfaceImageSourceFactory>();
|
||||
sisFactory->MockCreateInstanceWithDimensionsAndOpacity =
|
||||
|
@ -108,7 +114,7 @@ public:
|
|||
resourceCreator.Get(),
|
||||
width,
|
||||
height,
|
||||
CanvasBackground::Transparent,
|
||||
backgroundMode,
|
||||
sisFactory.Get(),
|
||||
dsFactory);
|
||||
}
|
||||
|
|
|
@ -305,12 +305,12 @@ TEST_CLASS(CanvasControlTests_SizeTests)
|
|||
return m_imageControl;
|
||||
}
|
||||
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height) override
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height, CanvasBackground backgroundMode) override
|
||||
{
|
||||
Assert::AreEqual(m_expectedImageSourceWidth, width, L"ExpectedImageSourceWidth");
|
||||
Assert::AreEqual(m_expectedImageSourceHeight, height, L"ExpectedImageSourceHeight");
|
||||
|
||||
return __super::CreateCanvasImageSource(device, width, height);
|
||||
return __super::CreateCanvasImageSource(device, width, height, backgroundMode);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -375,61 +375,84 @@ TEST_CLASS(CanvasControlTests_SizeTests)
|
|||
};
|
||||
};
|
||||
|
||||
class CanvasControlTestAdapter_InjectDeviceContext : public CanvasControlTestAdapter
|
||||
{
|
||||
ComPtr<ID2D1DeviceContext> m_deviceContext;
|
||||
|
||||
public:
|
||||
CanvasControlTestAdapter_InjectDeviceContext(ID2D1DeviceContext* deviceContext)
|
||||
: m_deviceContext(deviceContext)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(
|
||||
ICanvasDevice* device,
|
||||
int width,
|
||||
int height,
|
||||
CanvasBackground backgroundMode) override
|
||||
{
|
||||
auto result = CreateCanvasImageSourceMethod.WasCalled(device, width, height, backgroundMode);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
auto sisFactory = Make<MockSurfaceImageSourceFactory>();
|
||||
sisFactory->MockCreateInstanceWithDimensionsAndOpacity =
|
||||
[&](int32_t actualWidth, int32_t actualHeight, bool isOpaque, IInspectable* outer)
|
||||
{
|
||||
auto mockSurfaceImageSource = Make<MockSurfaceImageSource>();
|
||||
|
||||
mockSurfaceImageSource->BeginDrawMethod.AllowAnyCall(
|
||||
[&](RECT const&, IID const& iid, void** updateObject, POINT*)
|
||||
{
|
||||
return m_deviceContext.CopyTo(iid, updateObject);
|
||||
});
|
||||
|
||||
mockSurfaceImageSource->SetDeviceMethod.AllowAnyCall();
|
||||
mockSurfaceImageSource->EndDrawMethod.AllowAnyCall();
|
||||
|
||||
return mockSurfaceImageSource;
|
||||
};
|
||||
|
||||
auto dsFactory = std::make_shared<CanvasImageSourceDrawingSessionFactory>();
|
||||
|
||||
ComPtr<ICanvasResourceCreator> resourceCreator;
|
||||
ThrowIfFailed(device->QueryInterface(resourceCreator.GetAddressOf()));
|
||||
|
||||
return Make<CanvasImageSource>(
|
||||
resourceCreator.Get(),
|
||||
width,
|
||||
height,
|
||||
backgroundMode,
|
||||
sisFactory.Get(),
|
||||
dsFactory);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(CanvasControlTests_Dpi)
|
||||
{
|
||||
class CanvasControlTestAdapter_VerifyDpi : public CanvasControlTestAdapter
|
||||
class CanvasControlTestAdapter_VerifyDpi : public CanvasControlTestAdapter_InjectDeviceContext
|
||||
{
|
||||
public:
|
||||
float m_dpi;
|
||||
int m_lastImageSourceWidth;
|
||||
int m_lastImageSourceHeight;
|
||||
int m_imageSourceCount;
|
||||
ComPtr<ID2D1DeviceContext> m_d2dDeviceContext;
|
||||
|
||||
CanvasControlTestAdapter_VerifyDpi(ID2D1DeviceContext* d2dDeviceContext)
|
||||
: m_dpi(DEFAULT_DPI)
|
||||
CanvasControlTestAdapter_VerifyDpi(ID2D1DeviceContext* deviceContext)
|
||||
: CanvasControlTestAdapter_InjectDeviceContext(deviceContext)
|
||||
, m_dpi(DEFAULT_DPI)
|
||||
, m_lastImageSourceWidth(0)
|
||||
, m_lastImageSourceHeight(0)
|
||||
, m_d2dDeviceContext(d2dDeviceContext)
|
||||
, m_imageSourceCount(0)
|
||||
{}
|
||||
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height) override
|
||||
virtual ComPtr<CanvasImageSource> CreateCanvasImageSource(ICanvasDevice* device, int width, int height, CanvasBackground backgroundMode) override
|
||||
{
|
||||
m_lastImageSourceWidth = width;
|
||||
m_lastImageSourceHeight = height;
|
||||
m_imageSourceCount++;
|
||||
|
||||
auto sisFactory = Make<MockSurfaceImageSourceFactory>();
|
||||
sisFactory->MockCreateInstanceWithDimensionsAndOpacity =
|
||||
[&](int32_t actualWidth, int32_t actualHeight, bool isOpaque, IInspectable* outer)
|
||||
{
|
||||
auto mockSurfaceImageSource = Make<MockSurfaceImageSource>();
|
||||
|
||||
mockSurfaceImageSource->BeginDrawMethod.AllowAnyCall(
|
||||
[&](RECT const& updateRect, IID const& iid, void** updateObject, POINT* offset)
|
||||
{
|
||||
return m_d2dDeviceContext.CopyTo(iid, updateObject);
|
||||
});
|
||||
|
||||
mockSurfaceImageSource->SetDeviceMethod.AllowAnyCall();
|
||||
mockSurfaceImageSource->EndDrawMethod.AllowAnyCall();
|
||||
|
||||
return mockSurfaceImageSource;
|
||||
};
|
||||
|
||||
auto dsFactory = std::make_shared<CanvasImageSourceDrawingSessionFactory>();
|
||||
|
||||
ComPtr<ICanvasResourceCreator> resourceCreator;
|
||||
ThrowIfFailed(device->QueryInterface(resourceCreator.GetAddressOf()));
|
||||
|
||||
return Make<CanvasImageSource>(
|
||||
resourceCreator.Get(),
|
||||
width,
|
||||
height,
|
||||
CanvasBackground::Transparent,
|
||||
sisFactory.Get(),
|
||||
dsFactory);
|
||||
return __super::CreateCanvasImageSource(device, width, height, backgroundMode);
|
||||
}
|
||||
|
||||
virtual float GetLogicalDpi() override
|
||||
|
@ -454,6 +477,7 @@ TEST_CLASS(CanvasControlTests_Dpi)
|
|||
for (auto dpiCase : dpiCases)
|
||||
{
|
||||
auto adapter = std::make_shared<CanvasControlTestAdapter_VerifyDpi>(deviceContext.Get());
|
||||
adapter->CreateCanvasImageSourceMethod.AllowAnyCall();
|
||||
|
||||
int expectedImageSourceCount = 0;
|
||||
|
||||
|
@ -727,3 +751,163 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
TEST_CLASS(CanvasControl_ClearColor)
|
||||
{
|
||||
ComPtr<MockD2DDeviceContext> m_deviceContext;
|
||||
std::shared_ptr<CanvasControlTestAdapter> m_adapter;
|
||||
ComPtr<CanvasControl> m_control;
|
||||
ComPtr<StubUserControl> m_userControl;
|
||||
MockEventHandler<DrawEventHandlerType> m_onDraw;
|
||||
|
||||
public:
|
||||
TEST_METHOD_INITIALIZE(Init)
|
||||
{
|
||||
m_deviceContext = Make<MockD2DDeviceContext>();
|
||||
m_deviceContext->ClearMethod.AllowAnyCall();
|
||||
m_deviceContext->SetTransformMethod.AllowAnyCall();
|
||||
m_deviceContext->SetDpiMethod.AllowAnyCall();
|
||||
|
||||
m_adapter = std::make_shared<CanvasControlTestAdapter_InjectDeviceContext>(m_deviceContext.Get());
|
||||
m_control = Make<CanvasControl>(m_adapter);
|
||||
m_userControl = dynamic_cast<StubUserControl*>(As<IUserControl>(m_control).Get());
|
||||
|
||||
m_onDraw = MockEventHandler<DrawEventHandlerType>(L"Draw");
|
||||
|
||||
EventRegistrationToken ignoredToken;
|
||||
ThrowIfFailed(m_control->add_Draw(m_onDraw.Get(), &ignoredToken));
|
||||
|
||||
m_adapter->CreateCanvasImageSourceMethod.AllowAnyCall();
|
||||
m_userControl->LoadedEventSource->InvokeAll(nullptr, nullptr);
|
||||
|
||||
m_onDraw.SetExpectedCalls(1);
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_DefaultClearColorIsTransparentBlack)
|
||||
{
|
||||
Color expectedColor{ 0, 0, 0, 0 };
|
||||
|
||||
Color actualColor{ 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
ThrowIfFailed(m_control->get_ClearColor(&actualColor));
|
||||
|
||||
Assert::AreEqual(expectedColor, actualColor);
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_ClearColorValueIsPersisted)
|
||||
{
|
||||
Color anyColor{ 1, 2, 3, 4 };
|
||||
|
||||
ThrowIfFailed(m_control->put_ClearColor(anyColor));
|
||||
|
||||
Color actualColor{ 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
ThrowIfFailed(m_control->get_ClearColor(&actualColor));
|
||||
|
||||
Assert::AreEqual(anyColor, actualColor);
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_SettingDifferentClearColorTriggersRedraw)
|
||||
{
|
||||
Color currentColor;
|
||||
ThrowIfFailed(m_control->get_ClearColor(¤tColor));
|
||||
|
||||
Color differentColor = currentColor;
|
||||
differentColor.R = 255 - differentColor.R;
|
||||
|
||||
ThrowIfFailed(m_control->put_ClearColor(differentColor));
|
||||
|
||||
m_onDraw.SetExpectedCalls(1);
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
Expectations::Instance()->Validate();
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_SettingClearColorToCurrentValueDoesNotTriggerRedraw)
|
||||
{
|
||||
Color currentColor;
|
||||
ThrowIfFailed(m_control->get_ClearColor(¤tColor));
|
||||
|
||||
ThrowIfFailed(m_control->put_ClearColor(currentColor));
|
||||
|
||||
m_onDraw.SetExpectedCalls(0);
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
Expectations::Instance()->Validate();
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_DeviceContextIsClearedToCorrectColorBeforeDrawHandlerIsCalled)
|
||||
{
|
||||
Color anyColor{ 1, 2, 3, 4 };
|
||||
|
||||
m_onDraw.SetExpectedCalls(0);
|
||||
|
||||
m_deviceContext->ClearMethod.SetExpectedCalls(1,
|
||||
[&](D2D1_COLOR_F const* color)
|
||||
{
|
||||
Assert::AreEqual(ToD2DColor(anyColor), *color);
|
||||
m_onDraw.SetExpectedCalls(1);
|
||||
});
|
||||
|
||||
ThrowIfFailed(m_control->put_ClearColor(anyColor));
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
Expectations::Instance()->Validate();
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_WhenClearColorBecomesOpaque_SurfaceImageSourceIsCreatedWithOpaqueBackgroundMode)
|
||||
{
|
||||
m_onDraw.AllowAnyCall();
|
||||
|
||||
// The default clear color is transparent
|
||||
Color defaultClearColor;
|
||||
ThrowIfFailed(m_control->get_ClearColor(&defaultClearColor));
|
||||
Assert::AreNotEqual<uint8_t>(255, defaultClearColor.A);
|
||||
|
||||
Color anyOpaqueColor{ 255, 1, 2, 3 };
|
||||
ThrowIfFailed(m_control->put_ClearColor(anyOpaqueColor));
|
||||
|
||||
m_adapter->CreateCanvasImageSourceMethod.SetExpectedCalls(1,
|
||||
[&](ICanvasDevice*, int, int, CanvasBackground backgroundMode)
|
||||
{
|
||||
Assert::AreEqual(CanvasBackground::Opaque, backgroundMode);
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
Expectations::Instance()->Validate();
|
||||
}
|
||||
|
||||
TEST_METHOD(CanvasControl_WhenClearColorBecomesTransparent_SurfaceImageSourceIsCreatedWithTransparentBackgroundMode)
|
||||
{
|
||||
m_onDraw.AllowAnyCall();
|
||||
|
||||
// First ensure we have an opaque color set
|
||||
Color anyOpaqueColor{ 255, 1, 2, 3};
|
||||
ThrowIfFailed(m_control->put_ClearColor(anyOpaqueColor));
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
// Now set it to transparent
|
||||
Color anyTransparentColor{ 254, 1, 2, 3 };
|
||||
ThrowIfFailed(m_control->put_ClearColor(anyTransparentColor));
|
||||
|
||||
m_adapter->CreateCanvasImageSourceMethod.SetExpectedCalls(1,
|
||||
[&](ICanvasDevice*, int, int, CanvasBackground backgroundMode)
|
||||
{
|
||||
Assert::AreEqual(CanvasBackground::Transparent, backgroundMode);
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
RaiseAnyNumberOfCompositionRenderingEvents();
|
||||
|
||||
Expectations::Instance()->Validate();
|
||||
}
|
||||
|
||||
private:
|
||||
void RaiseAnyNumberOfCompositionRenderingEvents()
|
||||
{
|
||||
int anyNumberOfTimes = 5;
|
||||
for (auto i = 0; i < anyNumberOfTimes; ++i)
|
||||
m_adapter->RaiseCompositionRenderingEvent();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -374,7 +374,7 @@ private:
|
|||
// eg:
|
||||
//
|
||||
// auto onDraw = MockEventHandler<DrawEventHandlerType>(L"Draw");
|
||||
// onDraw.SetExpectedInvokes(1);
|
||||
// onDraw.SetExpectedCalls(1);
|
||||
// ThrowIfFailed(m_control->add_Draw(onDraw.Get(), &m_ignoredToken));
|
||||
//
|
||||
// The expectations are validated on destruction.
|
||||
|
@ -413,6 +413,11 @@ public:
|
|||
return m_callback.Get();
|
||||
}
|
||||
|
||||
void AllowAnyCall()
|
||||
{
|
||||
m_callCounter.AllowAnyCall();
|
||||
}
|
||||
|
||||
void SetExpectedCalls(int value)
|
||||
{
|
||||
m_callCounter.SetExpectedCalls(value);
|
||||
|
|
Загрузка…
Ссылка в новой задаче