|
@@ -0,0 +1,5699 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Jeff Muizelaar <jrmuizel@gmail.com>
|
|
|
+# Date 1546276838 18000
|
|
|
+# Node ID 1d586f7cf0c599b0152964b7bfd23f866547b4de
|
|
|
+# Parent 91bd06633f6b7c39a133e1c88c045d8db1a89463
|
|
|
+Bug 1517077. Remove Cairo D2D backend. r=lsalzman
|
|
|
+
|
|
|
+We don't use this anymore. Let's get rid of it.
|
|
|
+
|
|
|
+Differential Revision: https://phabricator.services.mozilla.com/D15557
|
|
|
+
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.fx b/gfx/cairo/cairo/src/cairo-d2d-private.fx
|
|
|
+deleted file mode 100644
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-d2d-private.fx
|
|
|
++++ /dev/null
|
|
|
+@@ -1,96 +0,0 @@
|
|
|
+-// We store vertex coordinates and the quad shape in a constant buffer, this is
|
|
|
+-// easy to update and allows us to use a single call to set the x, y, w, h of
|
|
|
+-// the quad.
|
|
|
+-// The QuadDesc and TexCoords both work as follows:
|
|
|
+-// The x component is the quad left point, the y component is the top point
|
|
|
+-// the z component is the width, and the w component is the height. The quad
|
|
|
+-// are specified in viewport coordinates, i.e. { -1.0f, 1.0f, 2.0f, -2.0f }
|
|
|
+-// would cover the entire viewport (which runs from <-1.0f, 1.0f> left to right
|
|
|
+-// and <-1.0f, 1.0f> -bottom- to top. The TexCoords desc is specified in texture
|
|
|
+-// space <0, 1.0f> left to right and top to bottom. The input vertices of the
|
|
|
+-// shader stage always form a rectangle from {0, 0} - {1, 1}
|
|
|
+-cbuffer cb0
|
|
|
+-{
|
|
|
+- float4 QuadDesc;
|
|
|
+- float4 TexCoords;
|
|
|
+- float4 TextColor;
|
|
|
+-}
|
|
|
+-
|
|
|
+-struct VS_OUTPUT
|
|
|
+-{
|
|
|
+- float4 Position : SV_Position;
|
|
|
+- float2 TexCoord : TEXCOORD0;
|
|
|
+-};
|
|
|
+-
|
|
|
+-struct PS_OUTPUT
|
|
|
+-{
|
|
|
+- float4 color;
|
|
|
+- float4 alpha;
|
|
|
+-};
|
|
|
+-
|
|
|
+-Texture2D tex;
|
|
|
+-
|
|
|
+-BlendState bTextBlend
|
|
|
+-{
|
|
|
+- AlphaToCoverageEnable = FALSE;
|
|
|
+- BlendEnable[0] = TRUE;
|
|
|
+- SrcBlend = Src1_Color;
|
|
|
+- DestBlend = Inv_Src1_Color;
|
|
|
+- BlendOp = Add;
|
|
|
+- SrcBlendAlpha = Src1_Alpha;
|
|
|
+- DestBlendAlpha = Inv_Src1_Alpha;
|
|
|
+- BlendOpAlpha = Add;
|
|
|
+- RenderTargetWriteMask[0] = 0x0F; // All
|
|
|
+-};
|
|
|
+-
|
|
|
+-sampler sSampler = sampler_state {
|
|
|
+- Texture = tex;
|
|
|
+- AddressU = Clamp;
|
|
|
+- AddressV = Clamp;
|
|
|
+-};
|
|
|
+-
|
|
|
+-VS_OUTPUT SampleTextureVS(float3 pos : POSITION)
|
|
|
+-{
|
|
|
+- VS_OUTPUT Output;
|
|
|
+- Output.Position.w = 1.0f;
|
|
|
+- Output.Position.x = pos.x * QuadDesc.z + QuadDesc.x;
|
|
|
+- Output.Position.y = pos.y * QuadDesc.w + QuadDesc.y;
|
|
|
+- Output.Position.z = 0;
|
|
|
+- Output.TexCoord.x = pos.x * TexCoords.z + TexCoords.x;
|
|
|
+- Output.TexCoord.y = pos.y * TexCoords.w + TexCoords.y;
|
|
|
+- return Output;
|
|
|
+-}
|
|
|
+-
|
|
|
+-float4 SampleTexturePS( VS_OUTPUT In) : SV_Target
|
|
|
+-{
|
|
|
+- return tex.Sample(sSampler, In.TexCoord);
|
|
|
+-};
|
|
|
+-
|
|
|
+-PS_OUTPUT SampleTextTexturePS( VS_OUTPUT In) : SV_Target
|
|
|
+-{
|
|
|
+- PS_OUTPUT output;
|
|
|
+- output.color = TextColor;
|
|
|
+- output.alpha.rgba = tex.Sample(sSampler, In.TexCoord).bgrg * TextColor.a;
|
|
|
+- return output;
|
|
|
+-};
|
|
|
+-
|
|
|
+-technique10 SampleTexture
|
|
|
+-{
|
|
|
+- pass P0
|
|
|
+- {
|
|
|
+- SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS()));
|
|
|
+- SetGeometryShader(NULL);
|
|
|
+- SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleTexturePS()));
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-technique10 SampleTextTexture
|
|
|
+-{
|
|
|
+- pass P0
|
|
|
+- {
|
|
|
+- SetBlendState(bTextBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
|
|
|
+- SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS()));
|
|
|
+- SetGeometryShader(NULL);
|
|
|
+- SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleTextTexturePS()));
|
|
|
+- }
|
|
|
+-}
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.h b/gfx/cairo/cairo/src/cairo-d2d-private.h
|
|
|
+deleted file mode 100644
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-d2d-private.h
|
|
|
++++ /dev/null
|
|
|
+@@ -1,191 +0,0 @@
|
|
|
+-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
|
|
+-/* Cairo - a vector graphics library with display and print output
|
|
|
+- *
|
|
|
+- * Copyright © 2010 Mozilla Foundation
|
|
|
+- *
|
|
|
+- * This library is free software; you can redistribute it and/or
|
|
|
+- * modify it either under the terms of the GNU Lesser General Public
|
|
|
+- * License version 2.1 as published by the Free Software Foundation
|
|
|
+- * (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
|
+- * Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
|
+- * notice, a recipient may use your version of this file under either
|
|
|
+- * the MPL or the LGPL.
|
|
|
+- *
|
|
|
+- * You should have received a copy of the LGPL along with this library
|
|
|
+- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
|
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
+- * You should have received a copy of the MPL along with this library
|
|
|
+- * in the file COPYING-MPL-1.1
|
|
|
+- *
|
|
|
+- * The contents of this file are subject to the Mozilla Public License
|
|
|
+- * Version 1.1 (the "License"); you may not use this file except in
|
|
|
+- * compliance with the License. You may obtain a copy of the License at
|
|
|
+- * http://www.mozilla.org/MPL/
|
|
|
+- *
|
|
|
+- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
|
+- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
|
+- * the specific language governing rights and limitations.
|
|
|
+- *
|
|
|
+- * The Original Code is the cairo graphics library.
|
|
|
+- *
|
|
|
+- * The Initial Developer of the Original Code is the Mozilla Foundation
|
|
|
+- *
|
|
|
+- * Contributor(s):
|
|
|
+- * Bas Schouten <bschouten@mozilla.com>
|
|
|
+- */
|
|
|
+-#ifndef CAIRO_D2D_PRIVATE_H
|
|
|
+-#define CAIRO_D2D_PRIVATE_H
|
|
|
+-
|
|
|
+-#ifdef CAIRO_HAS_D2D_SURFACE
|
|
|
+-
|
|
|
+-#include <windows.h>
|
|
|
+-#include <d2d1.h>
|
|
|
+-#include <d3d10.h>
|
|
|
+-#include <dxgi.h>
|
|
|
+-
|
|
|
+-#include "cairoint.h"
|
|
|
+-#include "cairo-surface-clipper-private.h"
|
|
|
+-
|
|
|
+-#include "cairo-win32-refptr.h"
|
|
|
+-#include "cairo-d2d-private-fx.h"
|
|
|
+-#include "cairo-win32.h"
|
|
|
+-#include "cairo-list-private.h"
|
|
|
+-
|
|
|
+-/* describes the type of the currently applied clip so that we can pop it */
|
|
|
+-struct d2d_clip_t;
|
|
|
+-
|
|
|
+-#define MAX_OPERATORS CAIRO_OPERATOR_HSL_LUMINOSITY + 1
|
|
|
+-
|
|
|
+-struct _cairo_d2d_device
|
|
|
+-{
|
|
|
+- cairo_device_t base;
|
|
|
+-
|
|
|
+- HMODULE mD3D10_1;
|
|
|
+- RefPtr<ID3D10Device1> mD3D10Device;
|
|
|
+- RefPtr<ID3D10Effect> mSampleEffect;
|
|
|
+- RefPtr<ID3D10InputLayout> mInputLayout;
|
|
|
+- RefPtr<ID3D10Buffer> mQuadBuffer;
|
|
|
+- RefPtr<ID3D10RasterizerState> mRasterizerState;
|
|
|
+- RefPtr<ID3D10BlendState> mBlendStates[MAX_OPERATORS];
|
|
|
+- /** Texture used for manual glyph rendering */
|
|
|
+- RefPtr<ID3D10Texture2D> mTextTexture;
|
|
|
+- RefPtr<ID3D10ShaderResourceView> mTextTextureView;
|
|
|
+- int mVRAMUsage;
|
|
|
+-};
|
|
|
+-
|
|
|
+-const unsigned int TEXT_TEXTURE_WIDTH = 2048;
|
|
|
+-const unsigned int TEXT_TEXTURE_HEIGHT = 512;
|
|
|
+-typedef struct _cairo_d2d_device cairo_d2d_device_t;
|
|
|
+-
|
|
|
+-struct _cairo_d2d_surface {
|
|
|
+- _cairo_d2d_surface() : d2d_clip(NULL), clipping(false), isDrawing(false),
|
|
|
+- textRenderingState(TEXT_RENDERING_UNINITIALIZED)
|
|
|
+- {
|
|
|
+- _cairo_clip_init (&this->clip);
|
|
|
+- cairo_list_init(&this->dependent_surfaces);
|
|
|
+- }
|
|
|
+-
|
|
|
+- ~_cairo_d2d_surface();
|
|
|
+-
|
|
|
+-
|
|
|
+- cairo_surface_t base;
|
|
|
+- /* Device used by this surface
|
|
|
+- * NOTE: In upstream cairo this is in the surface base class */
|
|
|
+- cairo_d2d_device_t *device;
|
|
|
+-
|
|
|
+- /** Render target of the texture we render to */
|
|
|
+- RefPtr<ID2D1RenderTarget> rt;
|
|
|
+- /** Surface containing our backstore */
|
|
|
+- RefPtr<ID3D10Resource> surface;
|
|
|
+- /**
|
|
|
+- * Surface used to temporarily store our surface if a bitmap isn't available
|
|
|
+- * straight from our render target surface.
|
|
|
+- */
|
|
|
+- RefPtr<ID3D10Texture2D> bufferTexture;
|
|
|
+- /** Backbuffer surface hwndrt renders to (NULL if not a window surface) */
|
|
|
+- RefPtr<IDXGISurface> backBuf;
|
|
|
+- /** Bitmap shared with texture and rendered to by rt */
|
|
|
+- RefPtr<ID2D1Bitmap> surfaceBitmap;
|
|
|
+- /** Swap chain holding our backbuffer (NULL if not a window surface) */
|
|
|
+- RefPtr<IDXGISwapChain> dxgiChain;
|
|
|
+- /** Window handle of the window we belong to */
|
|
|
+- HWND hwnd;
|
|
|
+- /** Format of the surface */
|
|
|
+- cairo_format_t format;
|
|
|
+-
|
|
|
+- cairo_clip_t clip;
|
|
|
+- d2d_clip_t *d2d_clip;
|
|
|
+-
|
|
|
+-
|
|
|
+- /** Mask layer used by surface_mask to push opacity masks */
|
|
|
+- RefPtr<ID2D1Layer> maskLayer;
|
|
|
+- /**
|
|
|
+- * Layer used for clipping when tiling, and also for clearing out geometries
|
|
|
+- * - lazily initialized
|
|
|
+- */
|
|
|
+- RefPtr<ID2D1Layer> helperLayer;
|
|
|
+- /** If this layer currently is clipping, used to prevent excessive push/pops */
|
|
|
+- bool clipping;
|
|
|
+- /** Brush used for bitmaps */
|
|
|
+- RefPtr<ID2D1BitmapBrush> bitmapBrush;
|
|
|
+- /** Brush used for solid colors */
|
|
|
+- RefPtr<ID2D1SolidColorBrush> solidColorBrush;
|
|
|
+- /** Indicates if our render target is currently in drawing mode */
|
|
|
+- bool isDrawing;
|
|
|
+- /** Indicates if text rendering is initialized */
|
|
|
+- enum TextRenderingState {
|
|
|
+- TEXT_RENDERING_UNINITIALIZED,
|
|
|
+- TEXT_RENDERING_NO_CLEARTYPE,
|
|
|
+- TEXT_RENDERING_NORMAL,
|
|
|
+- TEXT_RENDERING_GDI_CLASSIC
|
|
|
+- };
|
|
|
+- TextRenderingState textRenderingState;
|
|
|
+-
|
|
|
+- RefPtr<ID3D10RenderTargetView> buffer_rt_view;
|
|
|
+- RefPtr<ID3D10ShaderResourceView> buffer_sr_view;
|
|
|
+-
|
|
|
+- // Other d2d surfaces which depend on this one and need to be flushed if
|
|
|
+- // it is drawn to. This is required for situations where this surface is
|
|
|
+- // drawn to another surface, but may be modified before the other surface
|
|
|
+- // has flushed. When the flush of the other surface then happens and the
|
|
|
+- // drawing command is actually executed, the contents of this surface will
|
|
|
+- // no longer be what it was when the drawing command was issued.
|
|
|
+- cairo_list_t dependent_surfaces;
|
|
|
+- //cairo_surface_clipper_t clipper;
|
|
|
+-};
|
|
|
+-typedef struct _cairo_d2d_surface cairo_d2d_surface_t;
|
|
|
+-
|
|
|
+-struct _cairo_d2d_surface_entry
|
|
|
+-{
|
|
|
+- cairo_list_t link;
|
|
|
+- cairo_d2d_surface_t *surface;
|
|
|
+-};
|
|
|
+-
|
|
|
+-typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
|
|
|
+- D2D1_FACTORY_TYPE factoryType,
|
|
|
+- REFIID iid,
|
|
|
+- CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
|
|
|
+- void **factory
|
|
|
+-);
|
|
|
+-
|
|
|
+-typedef HRESULT (WINAPI*D3D10CreateDevice1Func)(
|
|
|
+- IDXGIAdapter *pAdapter,
|
|
|
+- D3D10_DRIVER_TYPE DriverType,
|
|
|
+- HMODULE Software,
|
|
|
+- UINT Flags,
|
|
|
+- D3D10_FEATURE_LEVEL1 HardwareLevel,
|
|
|
+- UINT SDKVersion,
|
|
|
+- ID3D10Device1 **ppDevice
|
|
|
+-);
|
|
|
+-
|
|
|
+-typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)(
|
|
|
+- void *pData,
|
|
|
+- SIZE_T DataLength,
|
|
|
+- UINT FXFlags,
|
|
|
+- ID3D10Device *pDevice,
|
|
|
+- ID3D10EffectPool *pEffectPool,
|
|
|
+- ID3D10Effect **ppEffect
|
|
|
+-);
|
|
|
+-
|
|
|
+-#endif /* CAIRO_HAS_D2D_SURFACE */
|
|
|
+-#endif /* CAIRO_D2D_PRIVATE_H */
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
|
|
|
+deleted file mode 100644
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
|
|
|
++++ /dev/null
|
|
|
+@@ -1,4864 +0,0 @@
|
|
|
+-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
|
|
|
+-/* Cairo - a vector graphics library with display and print output
|
|
|
+- *
|
|
|
+- * Copyright © 2010 Mozilla Foundation
|
|
|
+- *
|
|
|
+- * This library is free software; you can redistribute it and/or
|
|
|
+- * modify it either under the terms of the GNU Lesser General Public
|
|
|
+- * License version 2.1 as published by the Free Software Foundation
|
|
|
+- * (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
|
+- * Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
|
+- * notice, a recipient may use your version of this file under either
|
|
|
+- * the MPL or the LGPL.
|
|
|
+- *
|
|
|
+- * You should have received a copy of the LGPL along with this library
|
|
|
+- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
|
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
+- * You should have received a copy of the MPL along with this library
|
|
|
+- * in the file COPYING-MPL-1.1
|
|
|
+- *
|
|
|
+- * The contents of this file are subject to the Mozilla Public License
|
|
|
+- * Version 1.1 (the "License"); you may not use this file except in
|
|
|
+- * compliance with the License. You may obtain a copy of the License at
|
|
|
+- * http://www.mozilla.org/MPL/
|
|
|
+- *
|
|
|
+- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
|
+- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
|
+- * the specific language governing rights and limitations.
|
|
|
+- *
|
|
|
+- * The Original Code is the cairo graphics library.
|
|
|
+- *
|
|
|
+- * The Initial Developer of the Original Code is the Mozilla Foundation
|
|
|
+- *
|
|
|
+- * Contributor(s):
|
|
|
+- * Bas Schouten <bschouten@mozilla.com>
|
|
|
+- */
|
|
|
+-#define INITGUID
|
|
|
+-
|
|
|
+-#include "cairoint.h"
|
|
|
+-#include "cairo-d2d-private.h"
|
|
|
+-#include "cairo-dwrite-private.h"
|
|
|
+-
|
|
|
+-#include "cairo-win32.h"
|
|
|
+-#include "cairo-analysis-surface-private.h"
|
|
|
+-#include "cairo-error-private.h"
|
|
|
+-
|
|
|
+-// Required for using placement new.
|
|
|
+-#include <new>
|
|
|
+-
|
|
|
+-#include "d2d1_1.h"
|
|
|
+-
|
|
|
+-#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS
|
|
|
+-
|
|
|
+-struct Vertex
|
|
|
+-{
|
|
|
+- float position[2];
|
|
|
+-};
|
|
|
+-
|
|
|
+-// This factory is not device dependent, we can store it. But will clear it
|
|
|
+-// if there are no devices left needing it.
|
|
|
+-static ID2D1Factory *sD2DFactory = NULL;
|
|
|
+-static HMODULE sD2DModule;
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_release_factory()
|
|
|
+-{
|
|
|
+- int refcnt = sD2DFactory->Release();
|
|
|
+- if (!refcnt) {
|
|
|
+- // Once the last reference goes, free the library.
|
|
|
+- sD2DFactory = NULL;
|
|
|
+- FreeLibrary(sD2DModule);
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Set a blending mode for an operator. This will also return a boolean that
|
|
|
+- * reports if for this blend mode the entire surface needs to be blended. This
|
|
|
+- * is true whenever the DEST blend is not ONE when src alpha is 0.
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_set_operator(cairo_d2d_device_t *device,
|
|
|
+- cairo_operator_t op)
|
|
|
+-{
|
|
|
+- assert(op < MAX_OPERATORS);
|
|
|
+- if (op >= MAX_OPERATORS) {
|
|
|
+- // Eep! Someone forgot to update MAX_OPERATORS probably.
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (device->mBlendStates[static_cast<size_t>(op)]) {
|
|
|
+- device->mD3D10Device->OMSetBlendState(device->mBlendStates[op], NULL, 0xffffffff);
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D3D10_BLEND_DESC desc;
|
|
|
+- memset(&desc, 0, sizeof(desc));
|
|
|
+- desc.BlendEnable[0] = TRUE;
|
|
|
+- desc.AlphaToCoverageEnable = FALSE;
|
|
|
+- desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
|
|
|
+-
|
|
|
+- switch (op) {
|
|
|
+- case CAIRO_OPERATOR_OVER:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_ADD:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_IN:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_OUT:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_ATOP:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_DEST:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_DEST_OVER:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_DEST_IN:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_DEST_OUT:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_DEST_ATOP:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- case CAIRO_OPERATOR_XOR:
|
|
|
+- desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
|
|
|
+- desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
|
|
|
+- desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
|
|
|
+- break;
|
|
|
+- default:
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- };
|
|
|
+- device->mD3D10Device->CreateBlendState(&desc, &device->mBlendStates[op]);
|
|
|
+-
|
|
|
+- device->mD3D10Device->OMSetBlendState(device->mBlendStates[op], NULL, 0xffffffff);
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_device_t *
|
|
|
+-cairo_d2d_create_device_from_d3d10device(ID3D10Device1 *d3d10device)
|
|
|
+-{
|
|
|
+- HRESULT hr;
|
|
|
+- D3D10_RASTERIZER_DESC rastDesc;
|
|
|
+- D3D10_INPUT_ELEMENT_DESC layout[] =
|
|
|
+- {
|
|
|
+- { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
|
|
|
+- };
|
|
|
+- D3D10_PASS_DESC passDesc;
|
|
|
+- ID3D10EffectTechnique *technique;
|
|
|
+- Vertex vertices[] = { {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}} };
|
|
|
+- CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
|
|
|
+- D3D10_SUBRESOURCE_DATA data;
|
|
|
+- CD3D10_TEXTURE2D_DESC textDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
|
+- TEXT_TEXTURE_WIDTH,
|
|
|
+- TEXT_TEXTURE_HEIGHT,
|
|
|
+- 1, 1);
|
|
|
+-
|
|
|
+- cairo_d2d_device_t *device = new cairo_d2d_device_t;
|
|
|
+-
|
|
|
+- device->mD3D10Device = d3d10device;
|
|
|
+-
|
|
|
+- device->mD3D10_1 = LoadLibraryA("d3d10_1.dll");
|
|
|
+- D3D10CreateEffectFromMemoryFunc createEffect = (D3D10CreateEffectFromMemoryFunc)
|
|
|
+- GetProcAddress(device->mD3D10_1, "D3D10CreateEffectFromMemory");
|
|
|
+- D2D1CreateFactoryFunc createD2DFactory;
|
|
|
+-
|
|
|
+- if (!createEffect) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!sD2DFactory) {
|
|
|
+- sD2DModule = LoadLibraryW(L"d2d1.dll");
|
|
|
+- createD2DFactory = (D2D1CreateFactoryFunc)
|
|
|
+- GetProcAddress(sD2DModule, "D2D1CreateFactory");
|
|
|
+- if (!createD2DFactory) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+- D2D1_FACTORY_OPTIONS options;
|
|
|
+-#ifdef DEBUG
|
|
|
+- options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
|
|
|
+-#else
|
|
|
+- options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
|
|
|
+-#endif
|
|
|
+- hr = createD2DFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
|
|
+- __uuidof(ID2D1Factory),
|
|
|
+- &options,
|
|
|
+- (void**)&sD2DFactory);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- sD2DFactory->AddRef();
|
|
|
+- }
|
|
|
+-
|
|
|
+- device->mD3D10Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP);
|
|
|
+- createEffect((void*)g_main, sizeof(g_main), 0, device->mD3D10Device, NULL, &device->mSampleEffect);
|
|
|
+-
|
|
|
+- technique = device->mSampleEffect->GetTechniqueByName("SampleTexture");
|
|
|
+- technique->GetPassByIndex(0)->GetDesc(&passDesc);
|
|
|
+-
|
|
|
+-
|
|
|
+- hr = device->mD3D10Device->CreateInputLayout(layout,
|
|
|
+- sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC),
|
|
|
+- passDesc.pIAInputSignature,
|
|
|
+- passDesc.IAInputSignatureSize,
|
|
|
+- &device->mInputLayout);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- data.pSysMem = (void*)vertices;
|
|
|
+- hr = device->mD3D10Device->CreateBuffer(&bufferDesc, &data, &device->mQuadBuffer);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- memset(&rastDesc, 0, sizeof(rastDesc));
|
|
|
+- rastDesc.CullMode = D3D10_CULL_NONE;
|
|
|
+- rastDesc.FillMode = D3D10_FILL_SOLID;
|
|
|
+- rastDesc.DepthClipEnable = TRUE;
|
|
|
+- hr = device->mD3D10Device->CreateRasterizerState(&rastDesc, &device->mRasterizerState);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+- device->base.refcount = 1;
|
|
|
+-
|
|
|
+- // We start out with TEXT_TEXTURE roughly in VRAM usage.
|
|
|
+- device->mVRAMUsage = TEXT_TEXTURE_WIDTH * TEXT_TEXTURE_HEIGHT * 4;
|
|
|
+-
|
|
|
+- // We create this with USAGE_DEFAULT, our intention is to have VRAM reserved
|
|
|
+- // for text usage. We actually store glyph data in STAGING textures for the
|
|
|
+- // rendering pipeline to read and copy it to this VRAM texture.
|
|
|
+- textDesc.Usage = D3D10_USAGE_DEFAULT;
|
|
|
+- hr = device->mD3D10Device->CreateTexture2D(&textDesc, NULL, &device->mTextTexture);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAILED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- hr = device->mD3D10Device->CreateShaderResourceView(device->mTextTexture,
|
|
|
+- NULL,
|
|
|
+- &device->mTextTextureView);
|
|
|
+-
|
|
|
+- return &device->base;
|
|
|
+-FAILED:
|
|
|
+- delete &device->base;
|
|
|
+- return NULL;
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_device_t *
|
|
|
+-cairo_d2d_create_device()
|
|
|
+-{
|
|
|
+- HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
|
|
|
+- D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
|
|
|
+- GetProcAddress(d3d10module, "D3D10CreateDevice1");
|
|
|
+-
|
|
|
+- if (!createD3DDevice) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Device1> d3ddevice;
|
|
|
+-
|
|
|
+- /**
|
|
|
+- * On usage of D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS:
|
|
|
+- * documentation on D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
|
|
+- * can be misleading. In fact, that flag gives no such indication. I pointed this
|
|
|
+- * out to Bas in my email. However, Microsoft is in fact using this flag to
|
|
|
+- * indicate "light weight" DX applications. By light weight they are essentially
|
|
|
+- * referring to applications that are not games. The idea is that when you create
|
|
|
+- * a DX game, the driver assumes that you will pretty much have a single instance
|
|
|
+- * and therefore it doesn't try to hold back when it comes to GPU resource
|
|
|
+- * allocation as long as it can crank out performance. In other words, the
|
|
|
+- * priority in regular DX applications is to make that one application run as fast
|
|
|
+- * as you can. For "light weight" applications, including D2D applications, the
|
|
|
+- * priorities are a bit different. Now you are no longer going to have a single
|
|
|
+- * (or very few) instances. You can have a lot of them (say, for example, a
|
|
|
+- * separate DX context/device per browser tab). In such cases, the GPU resource
|
|
|
+- * allocation scheme changes.
|
|
|
+- */
|
|
|
+- HRESULT hr = createD3DDevice(
|
|
|
+- NULL,
|
|
|
+- D3D10_DRIVER_TYPE_HARDWARE,
|
|
|
+- NULL,
|
|
|
+- D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
|
|
+- D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
|
|
+- D3D10_FEATURE_LEVEL_10_1,
|
|
|
+- D3D10_1_SDK_VERSION,
|
|
|
+- &d3ddevice);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- hr = createD3DDevice(
|
|
|
+- NULL,
|
|
|
+- D3D10_DRIVER_TYPE_HARDWARE,
|
|
|
+- NULL,
|
|
|
+- D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
|
|
+- D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
|
|
+- D3D10_FEATURE_LEVEL_10_0,
|
|
|
+- D3D10_1_SDK_VERSION,
|
|
|
+- &d3ddevice);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- /* This is not guaranteed to be too fast! */
|
|
|
+- hr = createD3DDevice(
|
|
|
+- NULL,
|
|
|
+- D3D10_DRIVER_TYPE_HARDWARE,
|
|
|
+- NULL,
|
|
|
+- D3D10_CREATE_DEVICE_BGRA_SUPPORT |
|
|
|
+- D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
|
|
+- D3D10_FEATURE_LEVEL_9_3,
|
|
|
+- D3D10_1_SDK_VERSION,
|
|
|
+- &d3ddevice);
|
|
|
+-
|
|
|
+- }
|
|
|
+- }
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_device_t *device = cairo_d2d_create_device_from_d3d10device(d3ddevice);
|
|
|
+-
|
|
|
+- // Free our reference to the modules. The created device should have its own.
|
|
|
+- FreeLibrary(d3d10module);
|
|
|
+- return device;
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_release_device(cairo_device_t *device)
|
|
|
+-{
|
|
|
+- int newrefcnt = --device->refcount;
|
|
|
+- if (!newrefcnt) {
|
|
|
+- // Call the correct destructor
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- HMODULE d3d10_1 = d2d_device->mD3D10_1;
|
|
|
+- delete d2d_device;
|
|
|
+- _cairo_d2d_release_factory();
|
|
|
+- FreeLibrary(d3d10_1);
|
|
|
+- }
|
|
|
+- return newrefcnt;
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_addref_device(cairo_device_t *device)
|
|
|
+-{
|
|
|
+- return ++device->refcount;
|
|
|
+-}
|
|
|
+-
|
|
|
+-void
|
|
|
+-cairo_d2d_finish_device(cairo_device_t *device)
|
|
|
+-{
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- // Here it becomes interesting, this flush method is generally called when
|
|
|
+- // interop is going on between our device and another device. The
|
|
|
+- // synchronisation between these devices is not always that great. The
|
|
|
+- // device flush method may flush the device's command queue, but it gives
|
|
|
+- // no guarantee that the device will actually be done with those commands,
|
|
|
+- // and so the surface may still not be complete when the external device
|
|
|
+- // chooses to use it. The EVENT query will actually tell us when the GPU
|
|
|
+- // is completely done with our commands.
|
|
|
+- D3D10_QUERY_DESC queryDesc;
|
|
|
+- queryDesc.MiscFlags = 0;
|
|
|
+- queryDesc.Query = D3D10_QUERY_EVENT;
|
|
|
+- RefPtr<ID3D10Query> query;
|
|
|
+-
|
|
|
+- d2d_device->mD3D10Device->CreateQuery(&queryDesc, &query);
|
|
|
+-
|
|
|
+- // QUERY_EVENT does not use Begin(). It's disabled.
|
|
|
+- query->End();
|
|
|
+-
|
|
|
+- BOOL done = FALSE;
|
|
|
+- while (!done) {
|
|
|
+- // This will return S_OK and done = FALSE when the GPU is not done, and
|
|
|
+- // S_OK and done = TRUE when the GPU is done. Any other return value
|
|
|
+- // means we need to break out or risk an infinite loop.
|
|
|
+- if (FAILED(query->GetData(&done, sizeof(BOOL), 0))) {
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- if (FAILED(d2d_device->mD3D10Device->GetDeviceRemovedReason())) {
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-ID3D10Device1*
|
|
|
+-cairo_d2d_device_get_device(cairo_device_t *device)
|
|
|
+-{
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- return d2d_device->mD3D10Device;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_setup_for_blend(cairo_d2d_device_t *device)
|
|
|
+-{
|
|
|
+- device->mD3D10Device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
|
+- device->mD3D10Device->IASetInputLayout(device->mInputLayout);
|
|
|
+-
|
|
|
+- UINT stride = sizeof(Vertex);
|
|
|
+- UINT offset = 0;
|
|
|
+- ID3D10Buffer *buff = device->mQuadBuffer;
|
|
|
+- device->mD3D10Device->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
|
|
|
+-
|
|
|
+- device->mD3D10Device->RSSetState(device->mRasterizerState);
|
|
|
+-}
|
|
|
+-
|
|
|
+-// Contains our cache usage - perhaps this should be made threadsafe.
|
|
|
+-static int cache_usage = 0;
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a similar surface which will blend effectively to
|
|
|
+- * another surface. For D2D, this will create another texture.
|
|
|
+- * Within the types we use blending is always easy.
|
|
|
+- *
|
|
|
+- * \param surface Surface this needs to be similar to
|
|
|
+- * \param content Content type of the new surface
|
|
|
+- * \param width Width of the new surface
|
|
|
+- * \param height Height of the new surface
|
|
|
+- * \return New surface
|
|
|
+- */
|
|
|
+-static cairo_surface_t*
|
|
|
+-_cairo_d2d_create_similar(void *surface,
|
|
|
+- cairo_content_t content,
|
|
|
+- int width,
|
|
|
+- int height);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Release all the data held by a surface, the surface structure
|
|
|
+- * itsself will be freed by cairo.
|
|
|
+- *
|
|
|
+- * \param surface Surface to clean up
|
|
|
+- */
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_finish(void *surface);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get a read-only image surface that contains the pixel data
|
|
|
+- * of a D2D surface.
|
|
|
+- *
|
|
|
+- * \param abstract_surface D2D surface to acquire the image from
|
|
|
+- * \param image_out Pointer to where we should store the image surface pointer
|
|
|
+- * \param image_extra Pointer where to store extra data we want to know about
|
|
|
+- * at the point of release.
|
|
|
+- * \return CAIRO_STATUS_SUCCESS for success
|
|
|
+- */
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_acquire_source_image(void *abstract_surface,
|
|
|
+- cairo_image_surface_t **image_out,
|
|
|
+- void **image_extra);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Release a read-only image surface that was obtained using acquire_source_image
|
|
|
+- *
|
|
|
+- * \param abstract_surface D2D surface to acquire the image from
|
|
|
+- * \param image_out Pointer to where we should store the image surface pointer
|
|
|
+- * \param image_extra Pointer where to store extra data we want to know about
|
|
|
+- * at the point of release.
|
|
|
+- * \return CAIRO_STATUS_SUCCESS for success
|
|
|
+- */
|
|
|
+-static void
|
|
|
+-_cairo_d2d_release_source_image(void *abstract_surface,
|
|
|
+- cairo_image_surface_t *image,
|
|
|
+- void *image_extra);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get a read-write image surface that contains the pixel data
|
|
|
+- * of a D2D surface.
|
|
|
+- *
|
|
|
+- * \param abstract_surface D2D surface to acquire the image from
|
|
|
+- * \param image_out Pointer to where we should store the image surface pointer
|
|
|
+- * \param image_extra Pointer where to store extra data we want to know about
|
|
|
+- * at the point of release.
|
|
|
+- * \return CAIRO_STATUS_SUCCESS for success
|
|
|
+- */
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_acquire_dest_image(void *abstract_surface,
|
|
|
+- cairo_rectangle_int_t *interest_rect,
|
|
|
+- cairo_image_surface_t **image_out,
|
|
|
+- cairo_rectangle_int_t *image_rect,
|
|
|
+- void **image_extra);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Release a read-write image surface that was obtained using acquire_source_image
|
|
|
+- *
|
|
|
+- * \param abstract_surface D2D surface to acquire the image from
|
|
|
+- * \param image_out Pointer to where we should store the image surface pointer
|
|
|
+- * \param image_extra Pointer where to store extra data we want to know about
|
|
|
+- * at the point of release.
|
|
|
+- * \return CAIRO_STATUS_SUCCESS for success
|
|
|
+- */
|
|
|
+-static void
|
|
|
+-_cairo_d2d_release_dest_image(void *abstract_surface,
|
|
|
+- cairo_rectangle_int_t *interest_rect,
|
|
|
+- cairo_image_surface_t *image,
|
|
|
+- cairo_rectangle_int_t *image_rect,
|
|
|
+- void *image_extra);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Flush this surface, only after this operation is the related hardware texture
|
|
|
+- * guaranteed to contain all the results of the executed drawing operations.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface to flush
|
|
|
+- * \return CAIRO_STATUS_SUCCESS or CAIRO_SURFACE_TYPE_MISMATCH
|
|
|
+- */
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_flush(void *surface);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Fill a path on this D2D surface.
|
|
|
+- *
|
|
|
+- * \param surface The surface to apply this operation to, must be
|
|
|
+- * a D2D surface
|
|
|
+- * \param op The operator to use
|
|
|
+- * \param source The source pattern to fill this path with
|
|
|
+- * \param path The path to fill
|
|
|
+- * \param fill_rule The fill rule to uses on the path
|
|
|
+- * \param tolerance The tolerance applied to the filling
|
|
|
+- * \param antialias The anti-alias mode to use
|
|
|
+- * \param clip The clip of this operation
|
|
|
+- * \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
|
|
|
+- * CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_fill(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_path_fixed_t *path,
|
|
|
+- cairo_fill_rule_t fill_rule,
|
|
|
+- double tolerance,
|
|
|
+- cairo_antialias_t antialias,
|
|
|
+- cairo_clip_t *clip);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Paint this surface, applying the operation to the entire surface
|
|
|
+- *
|
|
|
+- * \param surface The surface to apply this operation to, must be
|
|
|
+- * a D2D surface
|
|
|
+- * \param op Operator to use when painting
|
|
|
+- * \param source The pattern to fill this surface with, source of the op
|
|
|
+- * \param clip The clip of this operation
|
|
|
+- * \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
|
|
|
+- * CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_paint(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_clip_t *clip);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Paint something on the surface applying a certain mask to that
|
|
|
+- * source.
|
|
|
+- *
|
|
|
+- * \param surface The surface to apply this oepration to, must be
|
|
|
+- * a D2D surface
|
|
|
+- * \param op Operator to use
|
|
|
+- * \param source Source for this operation
|
|
|
+- * \param mask Pattern to mask source with
|
|
|
+- * \param clip The clip of this operation
|
|
|
+- * \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
|
|
|
+- * CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_mask(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- const cairo_pattern_t *mask,
|
|
|
+- cairo_clip_t *clip);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Show a glyph run on the target D2D surface.
|
|
|
+- *
|
|
|
+- * \param surface The surface to apply this oepration to, must be
|
|
|
+- * a D2D surface
|
|
|
+- * \param op Operator to use
|
|
|
+- * \param source Source for this operation
|
|
|
+- * \param glyphs Glyphs to draw
|
|
|
+- * \param num_gluphs Amount of glyphs stored at glyphs
|
|
|
+- * \param scaled_font Scaled font to draw
|
|
|
+- * \param remaining_glyphs Pointer to store amount of glyphs still
|
|
|
+- * requiring drawing.
|
|
|
+- * \param clip The clip of this operation
|
|
|
+- * \return CAIRO_ERROR_SURFACE_TYPE_MISMATCH, CAIRO_ERROR_FONT_TYPE_MISMATCH,
|
|
|
+- * CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_show_glyphs (void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_glyph_t *glyphs,
|
|
|
+- int num_glyphs,
|
|
|
+- cairo_scaled_font_t *scaled_font,
|
|
|
+- cairo_clip_t *clip,
|
|
|
+- int *remaining_glyphs);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get the extents of this surface.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface to get the extents for
|
|
|
+- * \param extents Pointer to where to store the extents
|
|
|
+- * \param CAIRO_ERROR_SURFACE_TYPE_MISTMATCH or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_bool_t
|
|
|
+-_cairo_d2d_getextents(void *surface,
|
|
|
+- cairo_rectangle_int_t *extents);
|
|
|
+-
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Stroke a path on this D2D surface.
|
|
|
+- *
|
|
|
+- * \param surface The surface to apply this operation to, must be
|
|
|
+- * a D2D surface
|
|
|
+- * \param op The operator to use
|
|
|
+- * \param source The source pattern to fill this path with
|
|
|
+- * \param path The path to stroke
|
|
|
+- * \param style The style of the stroke
|
|
|
+- * \param ctm A logical to device matrix, since the path might be in
|
|
|
+- * device space the miter angle and such are not, hence we need to
|
|
|
+- * be aware of the transformation to apply correct stroking.
|
|
|
+- * \param ctm_inverse Inverse of ctm, used to transform the path back
|
|
|
+- * to logical space.
|
|
|
+- * \param tolerance Tolerance to stroke with
|
|
|
+- * \param antialias Antialias mode to use
|
|
|
+- * \param clip The clip of this operation
|
|
|
+- * \return Return code, this can be CAIRO_ERROR_SURFACE_TYPE_MISMATCH,
|
|
|
+- * CAIRO_INT_STATUS_UNSUPPORTED or CAIRO_STATUS_SUCCESS
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_stroke(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_path_fixed_t *path,
|
|
|
+- const cairo_stroke_style_t *style,
|
|
|
+- const cairo_matrix_t *ctm,
|
|
|
+- const cairo_matrix_t *ctm_inverse,
|
|
|
+- double tolerance,
|
|
|
+- cairo_antialias_t antialias,
|
|
|
+- cairo_clip_t *clip);
|
|
|
+-
|
|
|
+-static const cairo_surface_backend_t cairo_d2d_surface_backend = {
|
|
|
+- CAIRO_SURFACE_TYPE_D2D,
|
|
|
+- _cairo_d2d_create_similar, /* create_similar */
|
|
|
+- _cairo_d2d_finish, /* finish */
|
|
|
+- _cairo_d2d_acquire_source_image, /* acquire_source_image */
|
|
|
+- _cairo_d2d_release_source_image, /* release_source_image */
|
|
|
+- _cairo_d2d_acquire_dest_image, /* acquire_dest_image */
|
|
|
+- _cairo_d2d_release_dest_image, /* release_dest_image */
|
|
|
+- NULL, /* clone_similar */
|
|
|
+- NULL, /* composite */
|
|
|
+- NULL, /* fill_rectangles */
|
|
|
+- NULL, /* composite_trapezoids */
|
|
|
+- NULL, /* create_span_renderer */
|
|
|
+- NULL, /* check_span_renderer */
|
|
|
+- NULL, /* copy_page */
|
|
|
+- NULL, /* show_page */
|
|
|
+- _cairo_d2d_getextents, /* get_extents */
|
|
|
+- NULL, /* old_show_glyphs */
|
|
|
+- NULL, /* get_font_options */
|
|
|
+- _cairo_d2d_flush, /* flush */
|
|
|
+- NULL, /* mark_dirty_rectangle */
|
|
|
+- NULL, /* scaled_font_fini */
|
|
|
+- NULL, /* scaled_glyph_fini */
|
|
|
+- _cairo_d2d_paint, /* paint */
|
|
|
+- _cairo_d2d_mask, /* mask */
|
|
|
+- _cairo_d2d_stroke, /* stroke */
|
|
|
+- _cairo_d2d_fill, /* fill */
|
|
|
+- _cairo_d2d_show_glyphs, /* show_glyphs */
|
|
|
+- NULL, /* snapshot */
|
|
|
+- NULL
|
|
|
+-};
|
|
|
+-
|
|
|
+-/*
|
|
|
+- * Helper functions.
|
|
|
+- */
|
|
|
+-
|
|
|
+-/* Stack-based helper to manage region destruction. */
|
|
|
+-struct cairo_region_auto_ptr
|
|
|
+-{
|
|
|
+- cairo_region_auto_ptr() : region(NULL)
|
|
|
+- { }
|
|
|
+- cairo_region_auto_ptr(cairo_region_t *in_region) : region(in_region)
|
|
|
+- { }
|
|
|
+-
|
|
|
+- void set(cairo_region_t *in_region) { region = in_region; }
|
|
|
+-
|
|
|
+- ~cairo_region_auto_ptr() { if (region) cairo_region_destroy (region); }
|
|
|
+-
|
|
|
+- cairo_region_t *region;
|
|
|
+-};
|
|
|
+-
|
|
|
+-/* This clears a new D2D surface in case the VRAM was reused from an existing surface
|
|
|
+- * and is therefor not empty, this must be called outside of drawing state! */
|
|
|
+-static void
|
|
|
+-_d2d_clear_surface(cairo_d2d_surface_t *surf)
|
|
|
+-{
|
|
|
+- surf->rt->BeginDraw();
|
|
|
+- surf->rt->Clear(D2D1::ColorF(0, 0));
|
|
|
+- surf->rt->EndDraw();
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_rectangle_int_t
|
|
|
+-_cairo_rect_from_windows_rect(const RECT *rect)
|
|
|
+-{
|
|
|
+- cairo_rectangle_int_t new_rect;
|
|
|
+-
|
|
|
+- new_rect.x = rect->left;
|
|
|
+- new_rect.y = rect->top;
|
|
|
+- new_rect.width = rect->right - rect->left;
|
|
|
+- new_rect.height = rect->bottom - rect->top;
|
|
|
+-
|
|
|
+- return new_rect;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static D2D1_POINT_2F
|
|
|
+-_d2d_point_from_cairo_point(const cairo_point_t *point)
|
|
|
+-{
|
|
|
+- return D2D1::Point2F(_cairo_fixed_to_float(point->x),
|
|
|
+- _cairo_fixed_to_float(point->y));
|
|
|
+-}
|
|
|
+-
|
|
|
+-static D2D1_COLOR_F
|
|
|
+-_cairo_d2d_color_from_cairo_color(const cairo_color_t &color)
|
|
|
+-{
|
|
|
+- return D2D1::ColorF((FLOAT)color.red,
|
|
|
+- (FLOAT)color.green,
|
|
|
+- (FLOAT)color.blue,
|
|
|
+- (FLOAT)color.alpha);
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_round_out_to_int_rect(cairo_rectangle_int_t *rect, double x1, double y1, double x2, double y2)
|
|
|
+-{
|
|
|
+- rect->x = (int)floor(x1);
|
|
|
+- rect->y = (int)floor(y1);
|
|
|
+- rect->width = (int)ceil(x2) - rect->x;
|
|
|
+- rect->height = (int)ceil(y2) - rect->y;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static int
|
|
|
+-_cairo_d2d_compute_surface_mem_size(cairo_d2d_surface_t *surface)
|
|
|
+-{
|
|
|
+- int size = surface->rt->GetPixelSize().width * surface->rt->GetPixelSize().height;
|
|
|
+- size *= surface->rt->GetPixelFormat().format == DXGI_FORMAT_A8_UNORM ? 1 : 4;
|
|
|
+- return size;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static D2D1_COLOR_F
|
|
|
+-_cairo_d2d_color_from_cairo_color_stop(const cairo_color_stop_t &color)
|
|
|
+-{
|
|
|
+- return D2D1::ColorF((FLOAT)color.red,
|
|
|
+- (FLOAT)color.green,
|
|
|
+- (FLOAT)color.blue,
|
|
|
+- (FLOAT)color.alpha);
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Gets the surface buffer texture for window surfaces whose backbuffer
|
|
|
+- * is not directly usable as a bitmap.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface.
|
|
|
+- * \return Buffer texture
|
|
|
+- */
|
|
|
+-static ID3D10Texture2D*
|
|
|
+-_cairo_d2d_get_buffer_texture(cairo_d2d_surface_t *surface)
|
|
|
+-{
|
|
|
+- if (!surface->bufferTexture) {
|
|
|
+- RefPtr<IDXGISurface> surf;
|
|
|
+- DXGI_SURFACE_DESC surfDesc;
|
|
|
+- surface->surface->QueryInterface(&surf);
|
|
|
+- surf->GetDesc(&surfDesc);
|
|
|
+- CD3D10_TEXTURE2D_DESC softDesc(surfDesc.Format, surfDesc.Width, surfDesc.Height);
|
|
|
+- softDesc.MipLevels = 1;
|
|
|
+- softDesc.Usage = D3D10_USAGE_DEFAULT;
|
|
|
+- softDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
|
|
+- surface->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &surface->bufferTexture);
|
|
|
+- surface->device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(surface);
|
|
|
+- }
|
|
|
+- return surface->bufferTexture;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Ensure that the surface has an up-to-date surface bitmap. Used for
|
|
|
+- * window surfaces which cannot have a surface bitmap directly related
|
|
|
+- * to their backbuffer for some reason.
|
|
|
+- * You cannot create a bitmap around a backbuffer surface for reason (it will
|
|
|
+- * fail with an E_INVALIDARG). Meaning they need a special texture to store
|
|
|
+- * their graphical data which is wrapped by a D2D bitmap if a window surface
|
|
|
+- * is ever used in a surface pattern. All other D2D surfaces use a texture as
|
|
|
+- * their backing store so can have a bitmap directly.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface.
|
|
|
+- */
|
|
|
+-static void _cairo_d2d_update_surface_bitmap(cairo_d2d_surface_t *d2dsurf)
|
|
|
+-{
|
|
|
+- if (!d2dsurf->backBuf && d2dsurf->rt->GetPixelFormat().format != DXGI_FORMAT_A8_UNORM) {
|
|
|
+- return;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!d2dsurf->surfaceBitmap) {
|
|
|
+- d2dsurf->rt->CreateBitmap(d2dsurf->rt->GetPixelSize(),
|
|
|
+- D2D1::BitmapProperties(d2dsurf->rt->GetPixelFormat()),
|
|
|
+- &d2dsurf->surfaceBitmap);
|
|
|
+- }
|
|
|
+-
|
|
|
+- d2dsurf->surfaceBitmap->CopyFromRenderTarget(NULL, d2dsurf->rt, NULL);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Present the backbuffer for a surface create for an HWND. This needs
|
|
|
+- * to be called when the owner of the original window surface wants to
|
|
|
+- * actually present the executed drawing operations to the screen.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface.
|
|
|
+- */
|
|
|
+-void cairo_d2d_present_backbuffer(cairo_surface_t *surface)
|
|
|
+-{
|
|
|
+- if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return;
|
|
|
+- }
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- _cairo_d2d_flush(d2dsurf);
|
|
|
+- if (d2dsurf->dxgiChain) {
|
|
|
+- d2dsurf->dxgiChain->Present(0, 0);
|
|
|
+- d2dsurf->device->mD3D10Device->Flush();
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-struct d2d_clip_t
|
|
|
+-{
|
|
|
+- enum clip_type {LAYER, AXIS_ALIGNED_CLIP};
|
|
|
+- d2d_clip_t * const prev;
|
|
|
+- const enum clip_type type;
|
|
|
+- d2d_clip_t(d2d_clip_t *prev, clip_type type) : prev(prev), type(type) { }
|
|
|
+-};
|
|
|
+-
|
|
|
+-static RefPtr<ID2D1PathGeometry>
|
|
|
+-_cairo_d2d_create_path_geometry_for_path(cairo_path_fixed_t *path,
|
|
|
+- cairo_fill_rule_t fill_rule,
|
|
|
+- D2D1_FIGURE_BEGIN type);
|
|
|
+-
|
|
|
+-
|
|
|
+-static cairo_bool_t
|
|
|
+-box_is_integer (cairo_box_t *box)
|
|
|
+-{
|
|
|
+- return _cairo_fixed_is_integer(box->p1.x) &&
|
|
|
+- _cairo_fixed_is_integer(box->p1.y) &&
|
|
|
+- _cairo_fixed_is_integer(box->p2.x) &&
|
|
|
+- _cairo_fixed_is_integer(box->p2.y);
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-push_clip (cairo_d2d_surface_t *d2dsurf, cairo_clip_path_t *clip_path)
|
|
|
+-{
|
|
|
+- cairo_box_t box;
|
|
|
+- if (_cairo_path_fixed_is_box(&clip_path->path, &box)) {
|
|
|
+-
|
|
|
+- assert(box.p1.y < box.p2.y);
|
|
|
+-
|
|
|
+- D2D1_ANTIALIAS_MODE mode;
|
|
|
+- if (box_is_integer (&box)) {
|
|
|
+- mode = D2D1_ANTIALIAS_MODE_ALIASED;
|
|
|
+- } else {
|
|
|
+- mode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
|
|
|
+- }
|
|
|
+- d2dsurf->rt->PushAxisAlignedClip (
|
|
|
+- D2D1::RectF(
|
|
|
+- _cairo_fixed_to_float(box.p1.x),
|
|
|
+- _cairo_fixed_to_float(box.p1.y),
|
|
|
+- _cairo_fixed_to_float(box.p2.x),
|
|
|
+- _cairo_fixed_to_float(box.p2.y)),
|
|
|
+- mode);
|
|
|
+-
|
|
|
+- d2dsurf->d2d_clip = new d2d_clip_t (d2dsurf->d2d_clip, d2d_clip_t::AXIS_ALIGNED_CLIP);
|
|
|
+- } else {
|
|
|
+- HRESULT hr;
|
|
|
+- RefPtr<ID2D1PathGeometry> geom = _cairo_d2d_create_path_geometry_for_path (&clip_path->path,
|
|
|
+- clip_path->fill_rule,
|
|
|
+- D2D1_FIGURE_BEGIN_FILLED);
|
|
|
+- RefPtr<ID2D1Layer> layer;
|
|
|
+-
|
|
|
+- hr = d2dsurf->rt->CreateLayer (&layer);
|
|
|
+-
|
|
|
+- D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
|
|
|
+- D2D1_LAYER_OPTIONS1 options1 = D2D1_LAYER_OPTIONS1_NONE;
|
|
|
+-
|
|
|
+- if (d2dsurf->base.content == CAIRO_CONTENT_COLOR) {
|
|
|
+- options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
|
|
|
+- options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA;
|
|
|
+- options1 = D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1DeviceContext> dc;
|
|
|
+- hr = d2dsurf->rt->QueryInterface(IID_ID2D1DeviceContext, (void**)&dc);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- d2dsurf->rt->PushLayer(D2D1::LayerParameters(
|
|
|
+- D2D1::InfiniteRect(),
|
|
|
+- geom,
|
|
|
+- D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
|
+- D2D1::IdentityMatrix(),
|
|
|
+- 1.0,
|
|
|
+- 0,
|
|
|
+- options),
|
|
|
+- layer);
|
|
|
+- } else {
|
|
|
+- dc->PushLayer(D2D1::LayerParameters1(
|
|
|
+- D2D1::InfiniteRect(),
|
|
|
+- geom,
|
|
|
+- D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
|
+- D2D1::IdentityMatrix(),
|
|
|
+- 1.0,
|
|
|
+- 0,
|
|
|
+- options1),
|
|
|
+- layer);
|
|
|
+- }
|
|
|
+-
|
|
|
+- d2dsurf->d2d_clip = new d2d_clip_t(d2dsurf->d2d_clip, d2d_clip_t::LAYER);
|
|
|
+- }
|
|
|
+- if (!d2dsurf->d2d_clip)
|
|
|
+- return _cairo_error(CAIRO_STATUS_NO_MEMORY);
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-pop_clip (cairo_d2d_surface_t *d2dsurf)
|
|
|
+-{
|
|
|
+- d2d_clip_t *current_clip = d2dsurf->d2d_clip;
|
|
|
+-
|
|
|
+- /* pop the clip from the render target */
|
|
|
+- if (current_clip->type == d2d_clip_t::LAYER) {
|
|
|
+- d2dsurf->rt->PopLayer();
|
|
|
+- } else if (current_clip->type == d2d_clip_t::AXIS_ALIGNED_CLIP) {
|
|
|
+- d2dsurf->rt->PopAxisAlignedClip();
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* pop it from our own stack */
|
|
|
+- d2dsurf->d2d_clip = current_clip->prev;
|
|
|
+- delete current_clip;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/* intersect clip_paths until we reach head */
|
|
|
+-static cairo_status_t
|
|
|
+-clipper_intersect_clip_path_recursive (cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_clip_path_t *head,
|
|
|
+- cairo_clip_path_t *clip_path)
|
|
|
+-{
|
|
|
+- cairo_status_t status;
|
|
|
+-
|
|
|
+- if (clip_path->prev != head) {
|
|
|
+- status =
|
|
|
+- clipper_intersect_clip_path_recursive (d2dsurf,
|
|
|
+- head,
|
|
|
+- clip_path->prev);
|
|
|
+- if (unlikely (status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+- return push_clip(d2dsurf, clip_path);
|
|
|
+-
|
|
|
+-}
|
|
|
+-
|
|
|
+-/* pop all of the clipping layers and reset the clip */
|
|
|
+-static void
|
|
|
+-reset_clip (cairo_d2d_surface_t *d2dsurf)
|
|
|
+-{
|
|
|
+- cairo_clip_path_t *current_clip_path = d2dsurf->clip.path;
|
|
|
+- while (current_clip_path != NULL) {
|
|
|
+- pop_clip (d2dsurf);
|
|
|
+- current_clip_path = current_clip_path->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- _cairo_clip_reset (&d2dsurf->clip);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/* finds the lowest common ancestor of a and b */
|
|
|
+-static cairo_clip_path_t *
|
|
|
+-find_common_ancestor(cairo_clip_path_t *a, cairo_clip_path_t *b)
|
|
|
+-{
|
|
|
+- int a_depth = 0, b_depth = 0;
|
|
|
+-
|
|
|
+- cairo_clip_path_t *x;
|
|
|
+-
|
|
|
+- /* find the depths of the clip_paths */
|
|
|
+- x = a;
|
|
|
+- while (x) {
|
|
|
+- a_depth++;
|
|
|
+- x = x->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- x = b;
|
|
|
+- while (x) {
|
|
|
+- b_depth++;
|
|
|
+- x = x->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* rewind the deeper chain to the depth of the shallowest chain */
|
|
|
+- while (b_depth < a_depth && a) {
|
|
|
+- a = a->prev;
|
|
|
+- a_depth--;
|
|
|
+- }
|
|
|
+-
|
|
|
+- while (a_depth < b_depth && b) {
|
|
|
+- b = b->prev;
|
|
|
+- b_depth--;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* walk back until we find a common ancesstor */
|
|
|
+-
|
|
|
+- /* b will be null if and only if a is null because the depths
|
|
|
+- * must match at this point */
|
|
|
+- while (a) {
|
|
|
+- if (a == b)
|
|
|
+- return a;
|
|
|
+-
|
|
|
+- a = a->prev;
|
|
|
+- b = b->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* a will be NULL */
|
|
|
+- return a;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_set_clip (cairo_d2d_surface_t *d2dsurf, cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- if (clip == NULL) {
|
|
|
+- reset_clip (d2dsurf);
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (clip != NULL && clip->path == d2dsurf->clip.path)
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-
|
|
|
+- cairo_clip_path_t *current_clip_path = d2dsurf->clip.path;
|
|
|
+- cairo_clip_path_t *new_clip_path = clip->path;
|
|
|
+- cairo_clip_path_t *ancestor = find_common_ancestor (current_clip_path, new_clip_path);
|
|
|
+-
|
|
|
+- /* adjust the clip to the common ancestor */
|
|
|
+- while (current_clip_path != ancestor) {
|
|
|
+- pop_clip (d2dsurf);
|
|
|
+- current_clip_path = current_clip_path->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* we now have a common parent (current_clip_path) for the clip */
|
|
|
+-
|
|
|
+- /* replace the old clip */
|
|
|
+- _cairo_clip_reset (&d2dsurf->clip);
|
|
|
+- _cairo_clip_init_copy (&d2dsurf->clip, clip);
|
|
|
+-
|
|
|
+- /* push the new clip paths up to current_clip_path */
|
|
|
+- if (current_clip_path != clip->path)
|
|
|
+- return clipper_intersect_clip_path_recursive (d2dsurf, current_clip_path, clip->path);
|
|
|
+- else
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void _cairo_d2d_add_dependent_surface(cairo_d2d_surface_t *surf, cairo_d2d_surface_t *user)
|
|
|
+-{
|
|
|
+- _cairo_d2d_surface_entry *entry = new _cairo_d2d_surface_entry;
|
|
|
+- entry->surface = user;
|
|
|
+- cairo_surface_reference(&user->base);
|
|
|
+- cairo_list_add(&entry->link, &surf->dependent_surfaces);
|
|
|
+-};
|
|
|
+-
|
|
|
+-static void _cairo_d2d_flush_dependent_surfaces(cairo_d2d_surface_t *surf)
|
|
|
+-{
|
|
|
+- _cairo_d2d_surface_entry *entry, *next;
|
|
|
+- cairo_list_foreach_entry_safe(entry, next, _cairo_d2d_surface_entry, &surf->dependent_surfaces, link) {
|
|
|
+- _cairo_d2d_flush(entry->surface);
|
|
|
+- cairo_surface_destroy(&entry->surface->base);
|
|
|
+- delete entry;
|
|
|
+- }
|
|
|
+- cairo_list_init(&surf->dependent_surfaces);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Enter the state where the surface is ready for drawing. This will guarantee
|
|
|
+- * the surface is in the correct state, and the correct clipping area is pushed.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface
|
|
|
+- */
|
|
|
+-static void _begin_draw_state(cairo_d2d_surface_t* surface)
|
|
|
+-{
|
|
|
+- if (!surface->isDrawing) {
|
|
|
+- _cairo_d2d_flush_dependent_surfaces(surface);
|
|
|
+- surface->rt->BeginDraw();
|
|
|
+- surface->isDrawing = true;
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get a D2D matrix from a cairo matrix. Note that D2D uses row vectors where cairo
|
|
|
+- * uses column vectors. Hence the transposition.
|
|
|
+- *
|
|
|
+- * \param Cairo matrix
|
|
|
+- * \return D2D matrix
|
|
|
+- */
|
|
|
+-static D2D1::Matrix3x2F
|
|
|
+-_cairo_d2d_matrix_from_matrix(const cairo_matrix_t *matrix)
|
|
|
+-{
|
|
|
+- return D2D1::Matrix3x2F((FLOAT)matrix->xx,
|
|
|
+- (FLOAT)matrix->yx,
|
|
|
+- (FLOAT)matrix->xy,
|
|
|
+- (FLOAT)matrix->yy,
|
|
|
+- (FLOAT)matrix->x0,
|
|
|
+- (FLOAT)matrix->y0);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Returns the inverse matrix for a D2D1 matrix. We cannot use the Invert function
|
|
|
+- * on the Matrix3x2F function class since it's statically linked and we'd have to
|
|
|
+- * lookup the symbol in the library. Doing this ourselves is easier.
|
|
|
+- *
|
|
|
+- * \param mat matrix
|
|
|
+- * \return inverse of matrix mat
|
|
|
+- */
|
|
|
+-static D2D1::Matrix3x2F
|
|
|
+-_cairo_d2d_invert_matrix(const D2D1::Matrix3x2F &mat)
|
|
|
+-{
|
|
|
+- float inv_det = (1 / mat.Determinant());
|
|
|
+-
|
|
|
+- return D2D1::Matrix3x2F(mat._22 * inv_det,
|
|
|
+- -mat._12 * inv_det,
|
|
|
+- -mat._21 * inv_det,
|
|
|
+- mat._11 * inv_det,
|
|
|
+- (mat._21 * mat._32 - mat._22 * mat._31) * inv_det,
|
|
|
+- -(mat._11 * mat._32 - mat._12 * mat._31) * inv_det);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D2D stroke style interface for a cairo stroke style object. Must be
|
|
|
+- * released when the calling function is finished with it.
|
|
|
+- *
|
|
|
+- * \param style Cairo stroke style object
|
|
|
+- * \return D2D StrokeStyle interface
|
|
|
+- */
|
|
|
+-static RefPtr<ID2D1StrokeStyle>
|
|
|
+-_cairo_d2d_create_strokestyle_for_stroke_style(const cairo_stroke_style_t *style)
|
|
|
+-{
|
|
|
+- D2D1_CAP_STYLE line_cap = D2D1_CAP_STYLE_FLAT;
|
|
|
+- switch (style->line_cap) {
|
|
|
+- case CAIRO_LINE_CAP_BUTT:
|
|
|
+- line_cap = D2D1_CAP_STYLE_FLAT;
|
|
|
+- break;
|
|
|
+- case CAIRO_LINE_CAP_SQUARE:
|
|
|
+- line_cap = D2D1_CAP_STYLE_SQUARE;
|
|
|
+- break;
|
|
|
+- case CAIRO_LINE_CAP_ROUND:
|
|
|
+- line_cap = D2D1_CAP_STYLE_ROUND;
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_LINE_JOIN line_join = D2D1_LINE_JOIN_MITER;
|
|
|
+- switch (style->line_join) {
|
|
|
+- case CAIRO_LINE_JOIN_MITER:
|
|
|
+- line_join = D2D1_LINE_JOIN_MITER_OR_BEVEL;
|
|
|
+- break;
|
|
|
+- case CAIRO_LINE_JOIN_ROUND:
|
|
|
+- line_join = D2D1_LINE_JOIN_ROUND;
|
|
|
+- break;
|
|
|
+- case CAIRO_LINE_JOIN_BEVEL:
|
|
|
+- line_join = D2D1_LINE_JOIN_BEVEL;
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- FLOAT *dashes = NULL;
|
|
|
+- if (style->num_dashes) {
|
|
|
+- dashes = new FLOAT[style->num_dashes];
|
|
|
+- for (unsigned int i = 0; i < style->num_dashes; i++) {
|
|
|
+- /* D2D seems to specify dash lengths in units of
|
|
|
+- * line width instead of the more traditional approach
|
|
|
+- * that cairo and many other APIs use where the unit
|
|
|
+- * is in pixels or someother constant unit. */
|
|
|
+- dashes[i] = (FLOAT) (style->dash[i] / style->line_width);
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_DASH_STYLE dashStyle = D2D1_DASH_STYLE_SOLID;
|
|
|
+- if (dashes) {
|
|
|
+- dashStyle = D2D1_DASH_STYLE_CUSTOM;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1StrokeStyle> strokeStyle;
|
|
|
+- sD2DFactory->CreateStrokeStyle(D2D1::StrokeStyleProperties(line_cap,
|
|
|
+- line_cap,
|
|
|
+- line_cap,
|
|
|
+- line_join,
|
|
|
+- (FLOAT)style->miter_limit,
|
|
|
+- dashStyle,
|
|
|
+- (FLOAT)style->dash_offset),
|
|
|
+- dashes,
|
|
|
+- style->num_dashes,
|
|
|
+- &strokeStyle);
|
|
|
+- delete [] dashes;
|
|
|
+- return strokeStyle;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static int _d2d_compute_bitmap_mem_size(ID2D1Bitmap *bitmap)
|
|
|
+-{
|
|
|
+- D2D1_SIZE_U size = bitmap->GetPixelSize();
|
|
|
+- int bytes_per_pixel = bitmap->GetPixelFormat().format == DXGI_FORMAT_A8_UNORM ? 1 : 4;
|
|
|
+- return size.width * size.height * bytes_per_pixel;
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_user_data_key_t bitmap_key_nonextend;
|
|
|
+-cairo_user_data_key_t bitmap_key_extend;
|
|
|
+-cairo_user_data_key_t bitmap_key_snapshot;
|
|
|
+-
|
|
|
+-struct cached_bitmap {
|
|
|
+- cached_bitmap()
|
|
|
+- {
|
|
|
+- sD2DFactory->AddRef();
|
|
|
+- }
|
|
|
+-
|
|
|
+- ~cached_bitmap()
|
|
|
+- {
|
|
|
+- // Clear bitmap out first because it depends on the factory.
|
|
|
+- bitmap = NULL;
|
|
|
+- _cairo_d2d_release_factory();
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* Device this cached bitmap was created with, we should really have a per
|
|
|
+- * device cache, see bug 607408 */
|
|
|
+- cairo_d2d_device_t *device;
|
|
|
+- /** The cached bitmap */
|
|
|
+- RefPtr<ID2D1Bitmap> bitmap;
|
|
|
+- /** The cached bitmap is dirty and needs its data refreshed */
|
|
|
+- bool dirty;
|
|
|
+- /** Order of snapshot detach/release bitmap called not guaranteed, single threaded refcount for now */
|
|
|
+- int refs;
|
|
|
+-};
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * This is called when user data on a surface is replaced or the surface is
|
|
|
+- * destroyed.
|
|
|
+- */
|
|
|
+-static void _d2d_release_bitmap(void *bitmap)
|
|
|
+-{
|
|
|
+- cached_bitmap *existingBitmap = (cached_bitmap*)bitmap;
|
|
|
+- if (!--existingBitmap->refs) {
|
|
|
+- cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
|
|
|
+- delete existingBitmap;
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Via a little trick this is just used to determine when a surface has been
|
|
|
+- * modified.
|
|
|
+- */
|
|
|
+-static void _d2d_snapshot_detached(cairo_surface_t *surface)
|
|
|
+-{
|
|
|
+- cached_bitmap *existingBitmap = (cached_bitmap*)cairo_surface_get_user_data(surface, &bitmap_key_snapshot);
|
|
|
+- if (existingBitmap) {
|
|
|
+- existingBitmap->dirty = true;
|
|
|
+- }
|
|
|
+- if (!--existingBitmap->refs) {
|
|
|
+- cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
|
|
|
+- delete existingBitmap;
|
|
|
+- }
|
|
|
+- cairo_surface_destroy(surface);
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * This function will calculate the part of srcSurf which will possibly be used within
|
|
|
+- * the boundaries of d2dsurf given the current transformation mat. This is used to
|
|
|
+- * determine what the minimal part of a surface is that needs to be uploaded.
|
|
|
+- *
|
|
|
+- * \param d2dsurf D2D surface
|
|
|
+- * \param srcSurf Source surface for operation
|
|
|
+- * \param mat Transformation matrix applied to source
|
|
|
+- */
|
|
|
+-static void
|
|
|
+-_cairo_d2d_calculate_visible_rect(cairo_d2d_surface_t *d2dsurf, cairo_image_surface_t *srcSurf,
|
|
|
+- cairo_matrix_t *mat,
|
|
|
+- int *x, int *y, unsigned int *width, unsigned int *height)
|
|
|
+-{
|
|
|
+- /** Leave room for extend_none space, 2 pixels */
|
|
|
+- UINT32 maxSize = d2dsurf->rt->GetMaximumBitmapSize() - 2;
|
|
|
+-
|
|
|
+- /* Transform this surface to image surface space */
|
|
|
+- cairo_matrix_t invMat = *mat;
|
|
|
+- if (_cairo_matrix_is_invertible(mat)) {
|
|
|
+- /* If this is not invertible it will be rank zero, and invMat = mat is fine */
|
|
|
+- cairo_matrix_invert(&invMat);
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<IDXGISurface> surf;
|
|
|
+- d2dsurf->surface->QueryInterface(&surf);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+- surf->GetDesc(&desc);
|
|
|
+-
|
|
|
+- double leftMost = 0;
|
|
|
+- double rightMost = desc.Width;
|
|
|
+- double topMost = 0;
|
|
|
+- double bottomMost = desc.Height;
|
|
|
+-
|
|
|
+- _cairo_matrix_transform_bounding_box(&invMat, &leftMost, &topMost, &rightMost, &bottomMost, NULL);
|
|
|
+-
|
|
|
+- leftMost -= 1;
|
|
|
+- topMost -= 1;
|
|
|
+- rightMost += 1;
|
|
|
+- bottomMost += 1;
|
|
|
+-
|
|
|
+- /* Calculate the offsets into the source image and the width of the part required */
|
|
|
+- if ((UINT32)srcSurf->width > maxSize) {
|
|
|
+- *x = (int)MAX(0, floor(leftMost));
|
|
|
+- /* Ensure that we get atleast 1 column of pixels as source, this will make EXTEND_PAD work */
|
|
|
+- if (*x < srcSurf->width) {
|
|
|
+- *width = (unsigned int)MIN(MAX(1, ceil(rightMost - *x)), srcSurf->width - *x);
|
|
|
+- } else {
|
|
|
+- *x = srcSurf->width - 1;
|
|
|
+- *width = 1;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- *x = 0;
|
|
|
+- *width = srcSurf->width;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if ((UINT32)srcSurf->height > maxSize) {
|
|
|
+- *y = (int)MAX(0, floor(topMost));
|
|
|
+- /* Ensure that we get atleast 1 row of pixels as source, this will make EXTEND_PAD work */
|
|
|
+- if (*y < srcSurf->height) {
|
|
|
+- *height = (unsigned int)MIN(MAX(1, ceil(bottomMost - *y)), srcSurf->height - *y);
|
|
|
+- } else {
|
|
|
+- *y = srcSurf->height - 1;
|
|
|
+- *height = 1;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- *y = 0;
|
|
|
+- *height = srcSurf->height;
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-static double
|
|
|
+-_cairo_d2d_point_dist(const cairo_point_double_t &p1, const cairo_point_double_t &p2)
|
|
|
+-{
|
|
|
+- return hypot(p2.x - p1.x, p2.y - p1.y);
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_normalize_point(cairo_point_double_t *p)
|
|
|
+-{
|
|
|
+- double length = hypot(p->x, p->y);
|
|
|
+- p->x /= length;
|
|
|
+- p->y /= length;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_point_double_t
|
|
|
+-_cairo_d2d_subtract_point(const cairo_point_double_t &p1, const cairo_point_double_t &p2)
|
|
|
+-{
|
|
|
+- cairo_point_double_t p = {p1.x - p2.x, p1.y - p2.y};
|
|
|
+- return p;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static double
|
|
|
+-_cairo_d2d_dot_product(const cairo_point_double_t &p1, const cairo_point_double_t &p2)
|
|
|
+-{
|
|
|
+- return p1.x * p2.x + p1.y * p2.y;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static RefPtr<ID2D1Brush>
|
|
|
+-_cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_radial_pattern_t *source_pattern)
|
|
|
+-{
|
|
|
+- cairo_matrix_t inv_mat = source_pattern->base.base.matrix;
|
|
|
+- if (_cairo_matrix_is_invertible(&inv_mat)) {
|
|
|
+- /* If this is not invertible it will be rank zero, and invMat = mat is fine */
|
|
|
+- cairo_matrix_invert(&inv_mat);
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_BRUSH_PROPERTIES brushProps =
|
|
|
+- D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&inv_mat));
|
|
|
+-
|
|
|
+- if ((source_pattern->c1.x != source_pattern->c2.x ||
|
|
|
+- source_pattern->c1.y != source_pattern->c2.y) &&
|
|
|
+- source_pattern->r1 != 0) {
|
|
|
+- /**
|
|
|
+- * In this particular case there's no way to deal with this!
|
|
|
+- * \todo Create an image surface with the gradient and use that.
|
|
|
+- */
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D_POINT_2F center =
|
|
|
+- _d2d_point_from_cairo_point(&source_pattern->c2);
|
|
|
+- D2D_POINT_2F origin =
|
|
|
+- _d2d_point_from_cairo_point(&source_pattern->c1);
|
|
|
+- origin.x -= center.x;
|
|
|
+- origin.y -= center.y;
|
|
|
+-
|
|
|
+- float outer_radius = _cairo_fixed_to_float(source_pattern->r2);
|
|
|
+- float inner_radius = _cairo_fixed_to_float(source_pattern->r1);
|
|
|
+- int num_stops = source_pattern->base.n_stops;
|
|
|
+- D2D1_GRADIENT_STOP *stops;
|
|
|
+-
|
|
|
+- if (source_pattern->base.base.extend == CAIRO_EXTEND_REPEAT || source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
+- bool reflected = false;
|
|
|
+- bool reflect = source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT;
|
|
|
+-
|
|
|
+- RefPtr<IDXGISurface> surf;
|
|
|
+- d2dsurf->surface->QueryInterface(&surf);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+- surf->GetDesc(&desc);
|
|
|
+-
|
|
|
+- // Calculate the largest distance the origin could be from the edge after inverse
|
|
|
+- // transforming by the pattern transformation.
|
|
|
+- cairo_point_double_t top_left, top_right, bottom_left, bottom_right, gradient_center;
|
|
|
+- top_left.x = bottom_left.x = top_left.y = top_right.y = 0;
|
|
|
+- top_right.x = bottom_right.x = desc.Width;
|
|
|
+- bottom_right.y = bottom_left.y = desc.Height;
|
|
|
+-
|
|
|
+- gradient_center.x = _cairo_fixed_to_float(source_pattern->c1.x);
|
|
|
+- gradient_center.y = _cairo_fixed_to_float(source_pattern->c1.y);
|
|
|
+-
|
|
|
+- // Transform surface corners into pattern coordinates.
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y);
|
|
|
+-
|
|
|
+- // Find the corner furthest away from the gradient center in pattern space.
|
|
|
+- double largest = MAX(_cairo_d2d_point_dist(top_left, gradient_center), _cairo_d2d_point_dist(top_right, gradient_center));
|
|
|
+- largest = MAX(largest, _cairo_d2d_point_dist(bottom_left, gradient_center));
|
|
|
+- largest = MAX(largest, _cairo_d2d_point_dist(bottom_right, gradient_center));
|
|
|
+-
|
|
|
+- unsigned int minSize = (unsigned int)ceil(largest);
|
|
|
+-
|
|
|
+- // Calculate how often we need to repeat on the inside (for filling the inner radius)
|
|
|
+- // and on the outside (for covering the entire surface) and create the appropriate number
|
|
|
+- // of stops.
|
|
|
+- float gradient_length = outer_radius - inner_radius;
|
|
|
+- int inner_repeat = (int)ceil(inner_radius / gradient_length);
|
|
|
+- int outer_repeat = (int)MAX(1, ceil((minSize - inner_radius) / gradient_length));
|
|
|
+- num_stops *= (inner_repeat + outer_repeat);
|
|
|
+- stops = new D2D1_GRADIENT_STOP[num_stops];
|
|
|
+-
|
|
|
+- // Change outer_radius to the true outer radius after taking into account the needed
|
|
|
+- // repeats.
|
|
|
+- outer_radius = (inner_repeat + outer_repeat) * gradient_length;
|
|
|
+-
|
|
|
+- float stop_scale = 1.0f / (inner_repeat + outer_repeat);
|
|
|
+-
|
|
|
+- if (reflect) {
|
|
|
+- // We start out reflected (meaning reflected starts as false since it will
|
|
|
+- // immediately be inverted) if the inner_repeats are uneven.
|
|
|
+- reflected = !(inner_repeat & 0x1);
|
|
|
+-
|
|
|
+- for (int i = 0; i < num_stops; i++) {
|
|
|
+- if (!(i % source_pattern->base.n_stops)) {
|
|
|
+- // Reflect here
|
|
|
+- reflected = !reflected;
|
|
|
+- }
|
|
|
+- // Calculate the repeat count.
|
|
|
+- int repeat = i / source_pattern->base.n_stops;
|
|
|
+- // Take the stop that we're using in the pattern.
|
|
|
+- int stop = i % source_pattern->base.n_stops;
|
|
|
+- if (reflected) {
|
|
|
+- // Take the stop from the opposite side when reflected.
|
|
|
+- stop = source_pattern->base.n_stops - stop - 1;
|
|
|
+- // When reflected take 1 - offset as the offset.
|
|
|
+- stops[i].position = (FLOAT)((repeat + 1.0f - source_pattern->base.stops[stop].offset) * stop_scale);
|
|
|
+- } else {
|
|
|
+- stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale);
|
|
|
+- }
|
|
|
+- stops[i].color =
|
|
|
+- _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color);
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- // Simple case, we don't need to reflect.
|
|
|
+- for (int i = 0; i < num_stops; i++) {
|
|
|
+- // Calculate which repeat this is.
|
|
|
+- int repeat = i / source_pattern->base.n_stops;
|
|
|
+- // Calculate which stop this would be in the original pattern
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops];
|
|
|
+- stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale);
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- }
|
|
|
+- } else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) {
|
|
|
+- float offset_factor = (outer_radius - inner_radius) / outer_radius;
|
|
|
+- float global_offset = inner_radius / outer_radius;
|
|
|
+-
|
|
|
+- stops = new D2D1_GRADIENT_STOP[num_stops];
|
|
|
+-
|
|
|
+- // If the inner radius is not 0 we need to scale and offset the stops.
|
|
|
+- for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) {
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[i];
|
|
|
+- stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor);
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- } else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
|
|
|
+- float offset_factor = (outer_radius - inner_radius) / outer_radius;
|
|
|
+- float global_offset = inner_radius / outer_radius;
|
|
|
+-
|
|
|
+- num_stops++; // Add a stop on the outer radius.
|
|
|
+- if (inner_radius != 0) {
|
|
|
+- num_stops++; // Add a stop on the inner radius.
|
|
|
+- }
|
|
|
+-
|
|
|
+- stops = new D2D1_GRADIENT_STOP[num_stops];
|
|
|
+-
|
|
|
+- // If the inner radius is not 0 we need to scale and offset the stops and put a stop before the inner_radius
|
|
|
+- // of a transparent color.
|
|
|
+- int i = 0;
|
|
|
+- if (inner_radius != 0) {
|
|
|
+- stops[i].position = global_offset;
|
|
|
+- stops[i].color = D2D1::ColorF(0, 0);
|
|
|
+- i++;
|
|
|
+- }
|
|
|
+- for (unsigned int j = 0; j < source_pattern->base.n_stops; j++, i++) {
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[j];
|
|
|
+- stops[i].position = (FLOAT)(global_offset + stop->offset * offset_factor);
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- stops[i].position = 1.0f;
|
|
|
+- stops[i].color = D2D1::ColorF(0, 0);
|
|
|
+- } else {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1GradientStopCollection> stopCollection;
|
|
|
+- d2dsurf->rt->CreateGradientStopCollection(stops, num_stops, &stopCollection);
|
|
|
+- RefPtr<ID2D1RadialGradientBrush> brush;
|
|
|
+-
|
|
|
+- d2dsurf->rt->CreateRadialGradientBrush(D2D1::RadialGradientBrushProperties(center,
|
|
|
+- origin,
|
|
|
+- outer_radius,
|
|
|
+- outer_radius),
|
|
|
+- brushProps,
|
|
|
+- stopCollection,
|
|
|
+- &brush);
|
|
|
+- delete [] stops;
|
|
|
+- return brush;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static RefPtr<ID2D1Brush>
|
|
|
+-_cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_path_fixed_t *fill_path,
|
|
|
+- cairo_linear_pattern_t *source_pattern)
|
|
|
+-{
|
|
|
+- if (source_pattern->p1.x == source_pattern->p2.x &&
|
|
|
+- source_pattern->p1.y == source_pattern->p2.y) {
|
|
|
+- // Cairo behavior in this situation is to draw a solid color the size of the last stop.
|
|
|
+- RefPtr<ID2D1SolidColorBrush> brush;
|
|
|
+- d2dsurf->rt->CreateSolidColorBrush(
|
|
|
+- _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[source_pattern->base.n_stops - 1].color),
|
|
|
+- &brush);
|
|
|
+- return brush;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_matrix_t inv_mat = source_pattern->base.base.matrix;
|
|
|
+- /**
|
|
|
+- * Cairo views this matrix as the transformation of the destination
|
|
|
+- * when the pattern is imposed. We see this differently, D2D transformation
|
|
|
+- * moves the pattern over the destination.
|
|
|
+- */
|
|
|
+- if (_cairo_matrix_is_invertible(&inv_mat)) {
|
|
|
+- /* If this is not invertible it will be rank zero, and invMat = mat is fine */
|
|
|
+- cairo_matrix_invert(&inv_mat);
|
|
|
+- }
|
|
|
+- D2D1_BRUSH_PROPERTIES brushProps =
|
|
|
+- D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&inv_mat));
|
|
|
+- cairo_point_double_t p1, p2;
|
|
|
+- p1.x = _cairo_fixed_to_float(source_pattern->p1.x);
|
|
|
+- p1.y = _cairo_fixed_to_float(source_pattern->p1.y);
|
|
|
+- p2.x = _cairo_fixed_to_float(source_pattern->p2.x);
|
|
|
+- p2.y = _cairo_fixed_to_float(source_pattern->p2.y);
|
|
|
+-
|
|
|
+- D2D1_GRADIENT_STOP *stops;
|
|
|
+- int num_stops = source_pattern->base.n_stops;
|
|
|
+- if (source_pattern->base.base.extend == CAIRO_EXTEND_REPEAT || source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
+- // Get this when the points are not transformed yet.
|
|
|
+- double gradient_length = _cairo_d2d_point_dist(p1, p2);
|
|
|
+- cairo_point_double_t top_left, top_right, bottom_left, bottom_right;
|
|
|
+-
|
|
|
+- if (fill_path) {
|
|
|
+- // Calculate the repeat count needed;
|
|
|
+- cairo_box_t fill_extents;
|
|
|
+- _cairo_path_fixed_extents (fill_path, &fill_extents);
|
|
|
+-
|
|
|
+- top_left.x = bottom_left.x = _cairo_fixed_to_double (fill_extents.p1.x);
|
|
|
+- top_left.y = top_right.y = _cairo_fixed_to_double (fill_extents.p1.y);
|
|
|
+- top_right.x = bottom_right.x = _cairo_fixed_to_double (fill_extents.p2.x);
|
|
|
+- bottom_right.y = bottom_left.y = _cairo_fixed_to_double (fill_extents.p2.y);
|
|
|
+- } else {
|
|
|
+- RefPtr<IDXGISurface> surf;
|
|
|
+- d2dsurf->surface->QueryInterface(&surf);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+- surf->GetDesc(&desc);
|
|
|
+-
|
|
|
+- top_left.x = bottom_left.x = 0;
|
|
|
+- top_left.y = top_right.y = 0;
|
|
|
+- top_right.x = bottom_right.x = desc.Width;
|
|
|
+- bottom_right.y = bottom_left.y = desc.Height;
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Transform the corners of our surface to pattern space.
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_left.x, &top_left.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &top_right.x, &top_right.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_left.x, &bottom_left.y);
|
|
|
+- cairo_matrix_transform_point(&source_pattern->base.base.matrix, &bottom_right.x, &bottom_right.y);
|
|
|
+-
|
|
|
+- cairo_point_double_t u;
|
|
|
+- // Unit vector of the gradient direction.
|
|
|
+- u = _cairo_d2d_subtract_point(p2, p1);
|
|
|
+- _cairo_d2d_normalize_point(&u);
|
|
|
+-
|
|
|
+- // (corner - p1) . u = |corner - p1| cos(a) where a is the angle between the two vectors.
|
|
|
+- // Coincidentally |corner - p1| cos(a) is actually also the distance our gradient needs to cover since
|
|
|
+- // at this point on the gradient line it will be perpendicular to the line running from the gradient
|
|
|
+- // line through the corner.
|
|
|
+-
|
|
|
+- double max_dist, min_dist;
|
|
|
+- max_dist = MAX(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
|
|
|
+- _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
|
|
+- max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
|
|
|
+- max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
|
|
|
+- min_dist = MIN(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
|
|
|
+- _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
|
|
+- min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
|
|
|
+- min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
|
|
|
+-
|
|
|
+- min_dist = MAX(-min_dist, 0);
|
|
|
+-
|
|
|
+- // Repeats after gradient start.
|
|
|
+- // It's possible for max_dist and min_dist to both be zero, in which case
|
|
|
+- // we'll set num_stops to 0 and crash D2D. Let's just ensure after_repeat
|
|
|
+- // is at least 1.
|
|
|
+- int after_repeat = MAX((int)ceil(max_dist / gradient_length), 1);
|
|
|
+- int before_repeat = (int)ceil(min_dist / gradient_length);
|
|
|
+- num_stops *= (after_repeat + before_repeat);
|
|
|
+-
|
|
|
+- p2.x = p1.x + u.x * after_repeat * gradient_length;
|
|
|
+- p2.y = p1.y + u.y * after_repeat * gradient_length;
|
|
|
+- p1.x = p1.x - u.x * before_repeat * gradient_length;
|
|
|
+- p1.y = p1.y - u.y * before_repeat * gradient_length;
|
|
|
+-
|
|
|
+- float stop_scale = 1.0f / (float)(after_repeat + before_repeat);
|
|
|
+-
|
|
|
+- stops = new D2D1_GRADIENT_STOP[num_stops];
|
|
|
+- if (source_pattern->base.base.extend == CAIRO_EXTEND_REFLECT) {
|
|
|
+- // We start out reflected (meaning reflected starts as false since it will
|
|
|
+- // immediately be inverted) if the inner_repeats are uneven.
|
|
|
+- bool reflected = !(before_repeat & 0x1);
|
|
|
+-
|
|
|
+- for (int i = 0; i < num_stops; i++) {
|
|
|
+- if (!(i % source_pattern->base.n_stops)) {
|
|
|
+- // Reflect here
|
|
|
+- reflected = !reflected;
|
|
|
+- }
|
|
|
+- // Calculate the repeat count.
|
|
|
+- int repeat = i / source_pattern->base.n_stops;
|
|
|
+- // Take the stop that we're using in the pattern.
|
|
|
+- int stop = i % source_pattern->base.n_stops;
|
|
|
+- if (reflected) {
|
|
|
+- // Take the stop from the opposite side when reflected.
|
|
|
+- stop = source_pattern->base.n_stops - stop - 1;
|
|
|
+- // When reflected take 1 - offset as the offset.
|
|
|
+- stops[i].position = (FLOAT)((repeat + 1.0f - source_pattern->base.stops[stop].offset) * stop_scale);
|
|
|
+- } else {
|
|
|
+- stops[i].position = (FLOAT)((repeat + source_pattern->base.stops[stop].offset) * stop_scale);
|
|
|
+- }
|
|
|
+- stops[i].color =
|
|
|
+- _cairo_d2d_color_from_cairo_color_stop(source_pattern->base.stops[stop].color);
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- // Simple case, we don't need to reflect.
|
|
|
+- for (int i = 0; i < num_stops; i++) {
|
|
|
+- // Calculate which repeat this is.
|
|
|
+- int repeat = i / source_pattern->base.n_stops;
|
|
|
+- // Calculate which stop this would be in the original pattern
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[i % source_pattern->base.n_stops];
|
|
|
+- stops[i].position = (FLOAT)((repeat + stop->offset) * stop_scale);
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- }
|
|
|
+- } else if (source_pattern->base.base.extend == CAIRO_EXTEND_PAD) {
|
|
|
+- stops = new D2D1_GRADIENT_STOP[source_pattern->base.n_stops];
|
|
|
+- for (unsigned int i = 0; i < source_pattern->base.n_stops; i++) {
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[i];
|
|
|
+- stops[i].position = (FLOAT)stop->offset;
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- } else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
|
|
|
+- num_stops += 2;
|
|
|
+- stops = new D2D1_GRADIENT_STOP[num_stops];
|
|
|
+- stops[0].position = 0;
|
|
|
+- stops[0].color = D2D1::ColorF(0, 0);
|
|
|
+- for (unsigned int i = 1; i < source_pattern->base.n_stops + 1; i++) {
|
|
|
+- cairo_gradient_stop_t *stop = &source_pattern->base.stops[i - 1];
|
|
|
+- stops[i].position = (FLOAT)stop->offset;
|
|
|
+- stops[i].color = _cairo_d2d_color_from_cairo_color_stop(stop->color);
|
|
|
+- }
|
|
|
+- stops[source_pattern->base.n_stops + 1].position = 1.0f;
|
|
|
+- stops[source_pattern->base.n_stops + 1].color = D2D1::ColorF(0, 0);
|
|
|
+- }
|
|
|
+- RefPtr<ID2D1GradientStopCollection> stopCollection;
|
|
|
+- d2dsurf->rt->CreateGradientStopCollection(stops, num_stops, &stopCollection);
|
|
|
+- RefPtr<ID2D1LinearGradientBrush> brush;
|
|
|
+- d2dsurf->rt->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2D1::Point2F((FLOAT)p1.x, (FLOAT)p1.y),
|
|
|
+- D2D1::Point2F((FLOAT)p2.x, (FLOAT)p2.y)),
|
|
|
+- brushProps,
|
|
|
+- stopCollection,
|
|
|
+- &brush);
|
|
|
+- delete [] stops;
|
|
|
+- return brush;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * This creates an ID2D1Brush that will fill with the correct pattern.
|
|
|
+- * This function passes a -strong- reference to the caller, the brush
|
|
|
+- * needs to be released, even if it is not unique.
|
|
|
+- *
|
|
|
+- * \param d2dsurf Surface to create a brush for
|
|
|
+- * \param pattern The pattern to create a brush for
|
|
|
+- * \param unique We cache the bitmap/color brush for speed. If this
|
|
|
+- * needs a brush that is unique (i.e. when more than one is needed),
|
|
|
+- * this will make the function return a seperate brush.
|
|
|
+- * \return A brush object
|
|
|
+- */
|
|
|
+-static RefPtr<ID2D1Brush>
|
|
|
+-_cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_path_fixed_t *fill_path,
|
|
|
+- const cairo_pattern_t *pattern,
|
|
|
+- bool unique = false)
|
|
|
+-{
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
|
|
|
+- cairo_solid_pattern_t *sourcePattern =
|
|
|
+- (cairo_solid_pattern_t*)pattern;
|
|
|
+- D2D1_COLOR_F color = _cairo_d2d_color_from_cairo_color(sourcePattern->color);
|
|
|
+- if (unique) {
|
|
|
+- RefPtr<ID2D1SolidColorBrush> brush;
|
|
|
+- d2dsurf->rt->CreateSolidColorBrush(color,
|
|
|
+- &brush);
|
|
|
+- return brush;
|
|
|
+- } else {
|
|
|
+- if (d2dsurf->solidColorBrush->GetColor().a != color.a ||
|
|
|
+- d2dsurf->solidColorBrush->GetColor().r != color.r ||
|
|
|
+- d2dsurf->solidColorBrush->GetColor().g != color.g ||
|
|
|
+- d2dsurf->solidColorBrush->GetColor().b != color.b) {
|
|
|
+- d2dsurf->solidColorBrush->SetColor(color);
|
|
|
+- }
|
|
|
+- return d2dsurf->solidColorBrush;
|
|
|
+- }
|
|
|
+-
|
|
|
+- } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
|
|
|
+- cairo_linear_pattern_t *source_pattern =
|
|
|
+- (cairo_linear_pattern_t*)pattern;
|
|
|
+- return _cairo_d2d_create_linear_gradient_brush(d2dsurf, fill_path, source_pattern);
|
|
|
+- } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
|
|
|
+- cairo_radial_pattern_t *source_pattern =
|
|
|
+- (cairo_radial_pattern_t*)pattern;
|
|
|
+- return _cairo_d2d_create_radial_gradient_brush(d2dsurf, source_pattern);
|
|
|
+- } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
+- cairo_matrix_t mat = pattern->matrix;
|
|
|
+- cairo_matrix_invert(&mat);
|
|
|
+-
|
|
|
+- cairo_surface_pattern_t *surfacePattern =
|
|
|
+- (cairo_surface_pattern_t*)pattern;
|
|
|
+- D2D1_EXTEND_MODE extendMode;
|
|
|
+-
|
|
|
+- cairo_user_data_key_t *key = &bitmap_key_extend;
|
|
|
+-
|
|
|
+- if (pattern->extend == CAIRO_EXTEND_NONE) {
|
|
|
+- extendMode = D2D1_EXTEND_MODE_CLAMP;
|
|
|
+- key = &bitmap_key_nonextend;
|
|
|
+- /**
|
|
|
+- * We create a slightly larger bitmap with a transparent border
|
|
|
+- * around it for this case. Need to translate for that.
|
|
|
+- */
|
|
|
+- cairo_matrix_translate(&mat, -1.0, -1.0);
|
|
|
+- } else if (pattern->extend == CAIRO_EXTEND_REPEAT) {
|
|
|
+- extendMode = D2D1_EXTEND_MODE_WRAP;
|
|
|
+- } else if (pattern->extend == CAIRO_EXTEND_REFLECT) {
|
|
|
+- extendMode = D2D1_EXTEND_MODE_MIRROR;
|
|
|
+- } else {
|
|
|
+- extendMode = D2D1_EXTEND_MODE_CLAMP;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Bitmap> sourceBitmap;
|
|
|
+- bool partial = false;
|
|
|
+- int xoffset = 0;
|
|
|
+- int yoffset = 0;
|
|
|
+- unsigned int width;
|
|
|
+- unsigned int height;
|
|
|
+- unsigned char *data = NULL;
|
|
|
+- unsigned int stride = 0;
|
|
|
+-
|
|
|
+- if (surfacePattern->surface->type == CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- /**
|
|
|
+- * \todo We need to somehow get a rectangular transparent
|
|
|
+- * border here too!!
|
|
|
+- */
|
|
|
+- cairo_d2d_surface_t *srcSurf =
|
|
|
+- reinterpret_cast<cairo_d2d_surface_t*>(surfacePattern->surface);
|
|
|
+-
|
|
|
+- if (srcSurf == d2dsurf) {
|
|
|
+- /* D2D cannot deal with self-copy. We should add an optimized
|
|
|
+- * codepath for self-copy in the easy cases that does ping-pong like
|
|
|
+- * scroll does. See bug 579215. For now fallback.
|
|
|
+- */
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+- if (srcSurf->device != d2dsurf->device) {
|
|
|
+- /* This code does not work if the source surface does not use
|
|
|
+- * the same device. Some work could be done to do something
|
|
|
+- * fairly efficient here, for now, fallback.
|
|
|
+- */
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- _cairo_d2d_update_surface_bitmap(srcSurf);
|
|
|
+- _cairo_d2d_flush(srcSurf);
|
|
|
+-
|
|
|
+- // Mark a dependency on the source surface.
|
|
|
+- _cairo_d2d_add_dependent_surface(srcSurf, d2dsurf);
|
|
|
+-
|
|
|
+- if (pattern->extend == CAIRO_EXTEND_NONE) {
|
|
|
+- ID2D1Bitmap *srcSurfBitmap = srcSurf->surfaceBitmap;
|
|
|
+- d2dsurf->rt->CreateBitmap(
|
|
|
+- D2D1::SizeU(srcSurfBitmap->GetPixelSize().width + 2,
|
|
|
+- srcSurfBitmap->GetPixelSize().height + 2),
|
|
|
+- D2D1::BitmapProperties(srcSurfBitmap->GetPixelFormat()),
|
|
|
+- &sourceBitmap);
|
|
|
+- D2D1_POINT_2U point = D2D1::Point2U(1, 1);
|
|
|
+- sourceBitmap->CopyFromBitmap(&point, srcSurfBitmap, NULL);
|
|
|
+- } else {
|
|
|
+- sourceBitmap = srcSurf->surfaceBitmap;
|
|
|
+- }
|
|
|
+-
|
|
|
+- } else if (surfacePattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
|
|
|
+- cairo_image_surface_t *srcSurf =
|
|
|
+- reinterpret_cast<cairo_image_surface_t*>(surfacePattern->surface);
|
|
|
+- D2D1_ALPHA_MODE alpha;
|
|
|
+- if (srcSurf->format == CAIRO_FORMAT_ARGB32 ||
|
|
|
+- srcSurf->format == CAIRO_FORMAT_A8) {
|
|
|
+- alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
|
+- } else {
|
|
|
+- alpha = D2D1_ALPHA_MODE_IGNORE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- data = srcSurf->data;
|
|
|
+- stride = srcSurf->stride;
|
|
|
+-
|
|
|
+- /* This is used as a temporary surface for resampling surfaces larget than maxSize. */
|
|
|
+- pixman_image_t *pix_image = NULL;
|
|
|
+-
|
|
|
+- DXGI_FORMAT format;
|
|
|
+- unsigned int Bpp;
|
|
|
+- if (srcSurf->format == CAIRO_FORMAT_ARGB32) {
|
|
|
+- format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
+- Bpp = 4;
|
|
|
+- } else if (srcSurf->format == CAIRO_FORMAT_RGB24) {
|
|
|
+- format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
+- Bpp = 4;
|
|
|
+- } else if (srcSurf->format == CAIRO_FORMAT_A8) {
|
|
|
+- format = DXGI_FORMAT_A8_UNORM;
|
|
|
+- Bpp = 1;
|
|
|
+- } else {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /** Leave room for extend_none space, 2 pixels */
|
|
|
+- UINT32 maxSize = d2dsurf->rt->GetMaximumBitmapSize() - 2;
|
|
|
+-
|
|
|
+- if ((UINT32)srcSurf->width > maxSize || (UINT32)srcSurf->height > maxSize) {
|
|
|
+- if (pattern->extend == CAIRO_EXTEND_REPEAT ||
|
|
|
+- pattern->extend == CAIRO_EXTEND_REFLECT) {
|
|
|
+- // XXX - we don't have code to deal with these yet.
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* We cannot fit this image directly into a texture, start doing tricks to draw correctly anyway. */
|
|
|
+- partial = true;
|
|
|
+-
|
|
|
+- /* First we check which part of the image is inside the viewable area. */
|
|
|
+- _cairo_d2d_calculate_visible_rect(d2dsurf, srcSurf, &mat, &xoffset, &yoffset, &width, &height);
|
|
|
+-
|
|
|
+- cairo_matrix_translate(&mat, xoffset, yoffset);
|
|
|
+-
|
|
|
+- if (width > maxSize || height > maxSize) {
|
|
|
+- /*
|
|
|
+- * We cannot upload the required part of the surface directly, we're going to create
|
|
|
+- * a version which is downsampled to a smaller size by pixman and then uploaded.
|
|
|
+- *
|
|
|
+- * We need to size it to at least the diagonal size of this surface, in order to prevent ever
|
|
|
+- * upsampling this again when drawing it to the surface. We want the resized surface
|
|
|
+- * to be as small as possible to limit pixman required fill rate.
|
|
|
+- *
|
|
|
+- * Note this isn't necessarily perfect. Imagine having a 5x5 pixel destination and
|
|
|
+- * a 10x5 image containing a line of blackpixels, white pixels, black pixels, if you rotate
|
|
|
+- * this by 45 degrees and scale it to a size of 5x5 pixels and composite it to the destination,
|
|
|
+- * the composition will require all 10 original columns to do the best possible sampling.
|
|
|
+- */
|
|
|
+- RefPtr<IDXGISurface> surf;
|
|
|
+- d2dsurf->surface->QueryInterface(&surf);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+- surf->GetDesc(&desc);
|
|
|
+-
|
|
|
+- unsigned int minSize = (unsigned int)ceil(sqrt(pow((float)desc.Width, 2) + pow((float)desc.Height, 2)));
|
|
|
+-
|
|
|
+- unsigned int newWidth = MIN(minSize, MIN(width, maxSize));
|
|
|
+- unsigned int newHeight = MIN(minSize, MIN(height, maxSize));
|
|
|
+- double xRatio = (double)width / newWidth;
|
|
|
+- double yRatio = (double)height / newHeight;
|
|
|
+-
|
|
|
+- if (newWidth > maxSize || newHeight > maxSize) {
|
|
|
+- /*
|
|
|
+- * Okay, the diagonal of our surface is big enough to require a sampling larger
|
|
|
+- * than the maximum texture size. This is where we give up.
|
|
|
+- */
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* Create a temporary surface to hold the downsampled image */
|
|
|
+- pix_image = pixman_image_create_bits(srcSurf->pixman_format,
|
|
|
+- newWidth,
|
|
|
+- newHeight,
|
|
|
+- NULL,
|
|
|
+- -1);
|
|
|
+-
|
|
|
+- /* Set the transformation to downsample and call pixman_image_composite to downsample */
|
|
|
+- pixman_transform_t transform;
|
|
|
+- pixman_transform_init_scale(&transform, pixman_double_to_fixed(xRatio), pixman_double_to_fixed(yRatio));
|
|
|
+- pixman_transform_translate(&transform, NULL, pixman_int_to_fixed(xoffset), pixman_int_to_fixed(yoffset));
|
|
|
+-
|
|
|
+- pixman_image_set_transform(srcSurf->pixman_image, &transform);
|
|
|
+- pixman_image_composite(PIXMAN_OP_SRC, srcSurf->pixman_image, NULL, pix_image, 0, 0, 0, 0, 0, 0, newWidth, newHeight);
|
|
|
+-
|
|
|
+- /* Adjust the pattern transform to the used temporary surface */
|
|
|
+- cairo_matrix_scale(&mat, xRatio, yRatio);
|
|
|
+-
|
|
|
+- data = (unsigned char*)pixman_image_get_data(pix_image);
|
|
|
+- stride = pixman_image_get_stride(pix_image);
|
|
|
+-
|
|
|
+- /* Into this image we actually have no offset */
|
|
|
+- xoffset = 0;
|
|
|
+- yoffset = 0;
|
|
|
+- width = newWidth;
|
|
|
+- height = newHeight;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- width = srcSurf->width;
|
|
|
+- height = srcSurf->height;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cached_bitmap *cachebitmap = NULL;
|
|
|
+-
|
|
|
+- if (!partial) {
|
|
|
+- cachebitmap =
|
|
|
+- (cached_bitmap*)cairo_surface_get_user_data(
|
|
|
+- surfacePattern->surface,
|
|
|
+- key);
|
|
|
+- if (cachebitmap && cachebitmap->device != d2dsurf->device) {
|
|
|
+- cachebitmap = NULL;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (cachebitmap) {
|
|
|
+- sourceBitmap = cachebitmap->bitmap;
|
|
|
+- if (cachebitmap->dirty) {
|
|
|
+- D2D1_RECT_U rect;
|
|
|
+- /* No need to take partial uploading into account - partially uploaded surfaces are never cached. */
|
|
|
+- if (pattern->extend == CAIRO_EXTEND_NONE) {
|
|
|
+- rect = D2D1::RectU(1, 1, srcSurf->width + 1, srcSurf->height + 1);
|
|
|
+- } else {
|
|
|
+- rect = D2D1::RectU(0, 0, srcSurf->width, srcSurf->height);
|
|
|
+- }
|
|
|
+- sourceBitmap->CopyFromMemory(&rect,
|
|
|
+- srcSurf->data,
|
|
|
+- srcSurf->stride);
|
|
|
+- cairo_surface_t *nullSurf =
|
|
|
+- cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
|
|
|
+- cachebitmap->refs++;
|
|
|
+- cachebitmap->dirty = false;
|
|
|
+- cairo_surface_set_user_data(nullSurf,
|
|
|
+- &bitmap_key_snapshot,
|
|
|
+- cachebitmap,
|
|
|
+- NULL);
|
|
|
+- cairo_surface_attach_snapshot(surfacePattern->surface,
|
|
|
+- nullSurf,
|
|
|
+- _d2d_snapshot_detached);
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- if (pattern->extend != CAIRO_EXTEND_NONE) {
|
|
|
+- hr = d2dsurf->rt->CreateBitmap(D2D1::SizeU(width, height),
|
|
|
+- data + yoffset * stride + xoffset * Bpp,
|
|
|
+- stride,
|
|
|
+- D2D1::BitmapProperties(D2D1::PixelFormat(format,
|
|
|
+- alpha)),
|
|
|
+- &sourceBitmap);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- /**
|
|
|
+- * Trick here, we create a temporary rectangular
|
|
|
+- * surface with 1 pixel margin on each side. This
|
|
|
+- * provides a rectangular transparent border, that
|
|
|
+- * will ensure CLAMP acts as EXTEND_NONE. Perhaps
|
|
|
+- * this could be further optimized by not memsetting
|
|
|
+- * the whole array.
|
|
|
+- */
|
|
|
+- unsigned int tmpWidth = width + 2;
|
|
|
+- unsigned int tmpHeight = height + 2;
|
|
|
+- unsigned char *tmp = new unsigned char[tmpWidth * tmpHeight * Bpp];
|
|
|
+- memset(tmp, 0, tmpWidth * tmpHeight * Bpp);
|
|
|
+- for (unsigned int y = 0; y < height; y++) {
|
|
|
+- memcpy(
|
|
|
+- tmp + tmpWidth * Bpp * y + tmpWidth * Bpp + Bpp,
|
|
|
+- data + yoffset * stride + y * stride + xoffset * Bpp,
|
|
|
+- width * Bpp);
|
|
|
+- }
|
|
|
+-
|
|
|
+- hr = d2dsurf->rt->CreateBitmap(D2D1::SizeU(tmpWidth, tmpHeight),
|
|
|
+- tmp,
|
|
|
+- tmpWidth * Bpp,
|
|
|
+- D2D1::BitmapProperties(D2D1::PixelFormat(format,
|
|
|
+- D2D1_ALPHA_MODE_PREMULTIPLIED)),
|
|
|
+- &sourceBitmap);
|
|
|
+-
|
|
|
+- delete [] tmp;
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!partial) {
|
|
|
+- cached_bitmap *cachebitmap = new cached_bitmap;
|
|
|
+- /* We can cache it if it isn't a partial bitmap */
|
|
|
+- cachebitmap->dirty = false;
|
|
|
+- cachebitmap->bitmap = sourceBitmap;
|
|
|
+- cachebitmap->device = d2dsurf->device;
|
|
|
+- /*
|
|
|
+- * This will start out with two references, one on the snapshot
|
|
|
+- * and one more in the user data structure.
|
|
|
+- */
|
|
|
+- cachebitmap->refs = 2;
|
|
|
+- cairo_surface_set_user_data(surfacePattern->surface,
|
|
|
+- key,
|
|
|
+- cachebitmap,
|
|
|
+- _d2d_release_bitmap);
|
|
|
+- cairo_surface_t *nullSurf =
|
|
|
+- cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
|
|
|
+- cairo_surface_set_user_data(nullSurf,
|
|
|
+- &bitmap_key_snapshot,
|
|
|
+- cachebitmap,
|
|
|
+- NULL);
|
|
|
+- cairo_surface_attach_snapshot(surfacePattern->surface,
|
|
|
+- nullSurf,
|
|
|
+- _d2d_snapshot_detached);
|
|
|
+- cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);
|
|
|
+- }
|
|
|
+- if (pix_image) {
|
|
|
+- pixman_image_unref(pix_image);
|
|
|
+- }
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+- D2D1_BITMAP_BRUSH_PROPERTIES bitProps;
|
|
|
+-
|
|
|
+- if (surfacePattern->base.filter == CAIRO_FILTER_NEAREST) {
|
|
|
+- bitProps = D2D1::BitmapBrushProperties(extendMode,
|
|
|
+- extendMode,
|
|
|
+- D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR);
|
|
|
+- } else {
|
|
|
+- bitProps = D2D1::BitmapBrushProperties(extendMode,
|
|
|
+- extendMode,
|
|
|
+- D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
|
|
|
+- }
|
|
|
+- if (unique) {
|
|
|
+- RefPtr<ID2D1BitmapBrush> bitBrush;
|
|
|
+- D2D1_BRUSH_PROPERTIES brushProps =
|
|
|
+- D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&mat));
|
|
|
+- d2dsurf->rt->CreateBitmapBrush(sourceBitmap,
|
|
|
+- &bitProps,
|
|
|
+- &brushProps,
|
|
|
+- &bitBrush);
|
|
|
+- return bitBrush;
|
|
|
+- } else {
|
|
|
+- D2D1_MATRIX_3X2_F matrix = _cairo_d2d_matrix_from_matrix(&mat);
|
|
|
+-
|
|
|
+- if (d2dsurf->bitmapBrush) {
|
|
|
+- d2dsurf->bitmapBrush->SetTransform(matrix);
|
|
|
+-
|
|
|
+- if (surfacePattern->base.filter == CAIRO_FILTER_NEAREST) {
|
|
|
+- d2dsurf->bitmapBrush->SetInterpolationMode(D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR);
|
|
|
+- } else {
|
|
|
+- d2dsurf->bitmapBrush->SetInterpolationMode(D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
|
|
|
+- }
|
|
|
+-
|
|
|
+- d2dsurf->bitmapBrush->SetBitmap(sourceBitmap);
|
|
|
+- d2dsurf->bitmapBrush->SetExtendModeX(extendMode);
|
|
|
+- d2dsurf->bitmapBrush->SetExtendModeY(extendMode);
|
|
|
+- } else {
|
|
|
+- D2D1_BRUSH_PROPERTIES brushProps =
|
|
|
+- D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&mat));
|
|
|
+- d2dsurf->rt->CreateBitmapBrush(sourceBitmap,
|
|
|
+- &bitProps,
|
|
|
+- &brushProps,
|
|
|
+- &d2dsurf->bitmapBrush);
|
|
|
+- }
|
|
|
+- return d2dsurf->bitmapBrush;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-/** Path Conversion */
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Structure to use for the closure, containing all needed data.
|
|
|
+- */
|
|
|
+-struct path_conversion {
|
|
|
+- /** Geometry sink that we need to write to */
|
|
|
+- ID2D1GeometrySink *sink;
|
|
|
+- /**
|
|
|
+- * If this figure is active, cairo doesn't always send us a close. But
|
|
|
+- * we do need to end this figure if it didn't.
|
|
|
+- */
|
|
|
+- bool figureActive;
|
|
|
+- /**
|
|
|
+- * Current point, D2D has no explicit move so we need to track moved for
|
|
|
+- * the next begin.
|
|
|
+- */
|
|
|
+- cairo_point_t current_point;
|
|
|
+- /** The type of figure begin for this geometry instance */
|
|
|
+- D2D1_FIGURE_BEGIN type;
|
|
|
+-};
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_path_move_to(void *closure,
|
|
|
+- const cairo_point_t *point)
|
|
|
+-{
|
|
|
+- path_conversion *pathConvert =
|
|
|
+- static_cast<path_conversion*>(closure);
|
|
|
+- if (pathConvert->figureActive) {
|
|
|
+- pathConvert->sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
|
|
+- pathConvert->figureActive = false;
|
|
|
+- }
|
|
|
+-
|
|
|
+- pathConvert->current_point = *point;
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_path_line_to(void *closure,
|
|
|
+- const cairo_point_t *point)
|
|
|
+-{
|
|
|
+- path_conversion *pathConvert =
|
|
|
+- static_cast<path_conversion*>(closure);
|
|
|
+- if (!pathConvert->figureActive) {
|
|
|
+- pathConvert->sink->BeginFigure(_d2d_point_from_cairo_point(&pathConvert->current_point),
|
|
|
+- pathConvert->type);
|
|
|
+- pathConvert->figureActive = true;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_POINT_2F d2dpoint = _d2d_point_from_cairo_point(point);
|
|
|
+-
|
|
|
+- pathConvert->sink->AddLine(d2dpoint);
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_path_curve_to(void *closure,
|
|
|
+- const cairo_point_t *p0,
|
|
|
+- const cairo_point_t *p1,
|
|
|
+- const cairo_point_t *p2)
|
|
|
+-{
|
|
|
+- path_conversion *pathConvert =
|
|
|
+- static_cast<path_conversion*>(closure);
|
|
|
+- if (!pathConvert->figureActive) {
|
|
|
+- pathConvert->sink->BeginFigure(_d2d_point_from_cairo_point(&pathConvert->current_point),
|
|
|
+- D2D1_FIGURE_BEGIN_FILLED);
|
|
|
+- pathConvert->figureActive = true;
|
|
|
+- }
|
|
|
+-
|
|
|
+- pathConvert->sink->AddBezier(D2D1::BezierSegment(_d2d_point_from_cairo_point(p0),
|
|
|
+- _d2d_point_from_cairo_point(p1),
|
|
|
+- _d2d_point_from_cairo_point(p2)));
|
|
|
+-
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_path_close(void *closure)
|
|
|
+-{
|
|
|
+- path_conversion *pathConvert =
|
|
|
+- static_cast<path_conversion*>(closure);
|
|
|
+-
|
|
|
+- if (!pathConvert->figureActive) {
|
|
|
+- pathConvert->sink->BeginFigure(_d2d_point_from_cairo_point(&pathConvert->current_point),
|
|
|
+- pathConvert->type);
|
|
|
+- /**
|
|
|
+- * In this case we mean a single point. For D2D this means we need to add an infinitely
|
|
|
+- * small line here to get that effect.
|
|
|
+- */
|
|
|
+- pathConvert->sink->AddLine(_d2d_point_from_cairo_point(&pathConvert->current_point));
|
|
|
+- }
|
|
|
+-
|
|
|
+- pathConvert->sink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
|
|
+- pathConvert->figureActive = false;
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create an ID2D1PathGeometry for a cairo_path_fixed_t
|
|
|
+- *
|
|
|
+- * \param path Path to create a geometry for
|
|
|
+- * \param fill_rule Fill rule to use
|
|
|
+- * \param type Figure begin type to use
|
|
|
+- * \return A D2D geometry
|
|
|
+- */
|
|
|
+-static RefPtr<ID2D1PathGeometry>
|
|
|
+-_cairo_d2d_create_path_geometry_for_path(cairo_path_fixed_t *path,
|
|
|
+- cairo_fill_rule_t fill_rule,
|
|
|
+- D2D1_FIGURE_BEGIN type)
|
|
|
+-{
|
|
|
+- RefPtr<ID2D1PathGeometry> d2dpath;
|
|
|
+- sD2DFactory->CreatePathGeometry(&d2dpath);
|
|
|
+- RefPtr<ID2D1GeometrySink> sink;
|
|
|
+- d2dpath->Open(&sink);
|
|
|
+- D2D1_FILL_MODE fillMode = D2D1_FILL_MODE_WINDING;
|
|
|
+- if (fill_rule == CAIRO_FILL_RULE_WINDING) {
|
|
|
+- fillMode = D2D1_FILL_MODE_WINDING;
|
|
|
+- } else if (fill_rule == CAIRO_FILL_RULE_EVEN_ODD) {
|
|
|
+- fillMode = D2D1_FILL_MODE_ALTERNATE;
|
|
|
+- }
|
|
|
+- sink->SetFillMode(fillMode);
|
|
|
+-
|
|
|
+- path_conversion pathConvert;
|
|
|
+- pathConvert.type = type;
|
|
|
+- pathConvert.sink = sink;
|
|
|
+- pathConvert.figureActive = false;
|
|
|
+- _cairo_path_fixed_interpret(path,
|
|
|
+- CAIRO_DIRECTION_FORWARD,
|
|
|
+- _cairo_d2d_path_move_to,
|
|
|
+- _cairo_d2d_path_line_to,
|
|
|
+- _cairo_d2d_path_curve_to,
|
|
|
+- _cairo_d2d_path_close,
|
|
|
+- &pathConvert);
|
|
|
+- if (pathConvert.figureActive) {
|
|
|
+- sink->EndFigure(D2D1_FIGURE_END_OPEN);
|
|
|
+- }
|
|
|
+- sink->Close();
|
|
|
+- return d2dpath;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_bool_t
|
|
|
+-clip_contains_only_boxes (cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_bool_t is_boxes = TRUE;
|
|
|
+-
|
|
|
+- if (clip) {
|
|
|
+- cairo_box_t clip_box;
|
|
|
+- cairo_clip_path_t *path = clip->path;
|
|
|
+-
|
|
|
+- while (path) {
|
|
|
+- is_boxes &= _cairo_path_fixed_is_box(&path->path, &clip_box);
|
|
|
+- path = path->prev;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- return is_boxes;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_clear_box (cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_clip_t *clip,
|
|
|
+- cairo_box_t *box)
|
|
|
+-{
|
|
|
+- if (clip_contains_only_boxes (clip)) {
|
|
|
+- /* clear the box using axis aligned clips */
|
|
|
+- d2dsurf->rt->PushAxisAlignedClip(D2D1::RectF(_cairo_fixed_to_float(box->p1.x),
|
|
|
+- _cairo_fixed_to_float(box->p1.y),
|
|
|
+- _cairo_fixed_to_float(box->p2.x),
|
|
|
+- _cairo_fixed_to_float(box->p2.y)),
|
|
|
+- D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
+- d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
|
|
|
+- d2dsurf->rt->PopAxisAlignedClip();
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_clear (cairo_d2d_surface_t *d2dsurf,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_region_t *region;
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- if (!clip) {
|
|
|
+- /* no clip so clear everything */
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+- reset_clip(d2dsurf);
|
|
|
+- d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- status = _cairo_clip_get_region (clip, ®ion);
|
|
|
+- if (status)
|
|
|
+- return status;
|
|
|
+-
|
|
|
+- /* We now have a region, we'll clear it one rectangle at a time */
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+-
|
|
|
+- reset_clip(d2dsurf);
|
|
|
+-
|
|
|
+- if (region) {
|
|
|
+- int num_rects;
|
|
|
+- int i;
|
|
|
+-
|
|
|
+- num_rects = cairo_region_num_rectangles (region);
|
|
|
+-
|
|
|
+- for (i = 0; i < num_rects; i++) {
|
|
|
+- cairo_rectangle_int_t rect;
|
|
|
+-
|
|
|
+- cairo_region_get_rectangle (region, i, &rect);
|
|
|
+-
|
|
|
+- d2dsurf->rt->PushAxisAlignedClip(
|
|
|
+- D2D1::RectF((FLOAT)rect.x,
|
|
|
+- (FLOAT)rect.y,
|
|
|
+- (FLOAT)rect.x + rect.width,
|
|
|
+- (FLOAT)rect.y + rect.height),
|
|
|
+- D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
+-
|
|
|
+- d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
|
|
|
+-
|
|
|
+- d2dsurf->rt->PopAxisAlignedClip();
|
|
|
+- }
|
|
|
+-
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source)
|
|
|
+-{
|
|
|
+- if (op == CAIRO_OPERATOR_SOURCE) {
|
|
|
+- /** Operator over is easier for D2D! If the source if opaque, change */
|
|
|
+- if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
+- const cairo_surface_pattern_t *surfpattern =
|
|
|
+- reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
|
|
+- if (surfpattern->surface->content == CAIRO_CONTENT_COLOR) {
|
|
|
+- return CAIRO_OPERATOR_OVER;
|
|
|
+- }
|
|
|
+- } else if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
|
|
|
+- const cairo_solid_pattern_t *solidpattern =
|
|
|
+- reinterpret_cast<const cairo_solid_pattern_t*>(source);
|
|
|
+- if (solidpattern->color.alpha == 1.0) {
|
|
|
+- return CAIRO_OPERATOR_OVER;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- }
|
|
|
+- return op;
|
|
|
+-}
|
|
|
+-
|
|
|
+-void
|
|
|
+-_cairo_d2d_surface_init(cairo_d2d_surface_t *newSurf, cairo_d2d_device_t *d2d_device, cairo_format_t format)
|
|
|
+-{
|
|
|
+- newSurf->format = format;
|
|
|
+-
|
|
|
+- newSurf->device = d2d_device;
|
|
|
+- cairo_addref_device(&d2d_device->base);
|
|
|
+- d2d_device->mVRAMUsage += _cairo_d2d_compute_surface_mem_size(newSurf);
|
|
|
+-}
|
|
|
+-
|
|
|
+-_cairo_d2d_surface::~_cairo_d2d_surface()
|
|
|
+-{
|
|
|
+- _cairo_d2d_surface_entry *entry, *next;
|
|
|
+- cairo_list_foreach_entry_safe(entry, next, _cairo_d2d_surface_entry, &dependent_surfaces, link) {
|
|
|
+- // We do not need to flush, the contents of our texture has not changed,
|
|
|
+- // our users have their own reference and can just use it later.
|
|
|
+- cairo_surface_destroy(&entry->surface->base);
|
|
|
+- delete entry;
|
|
|
+- }
|
|
|
+-
|
|
|
+-}
|
|
|
+-
|
|
|
+-// Implementation
|
|
|
+-static cairo_surface_t*
|
|
|
+-_cairo_d2d_create_similar(void *surface,
|
|
|
+- cairo_content_t content,
|
|
|
+- int width,
|
|
|
+- int height)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
|
|
+-
|
|
|
+- new (newSurf) cairo_d2d_surface_t();
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
|
|
|
+-
|
|
|
+-
|
|
|
+- D2D1_SIZE_U sizePixels;
|
|
|
+- D2D1_SIZE_F size;
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- sizePixels.width = width;
|
|
|
+- sizePixels.height = height;
|
|
|
+- FLOAT dpiX;
|
|
|
+- FLOAT dpiY;
|
|
|
+-
|
|
|
+- d2dsurf->rt->GetDpi(&dpiX, &dpiY);
|
|
|
+-
|
|
|
+- D2D1_ALPHA_MODE alpha;
|
|
|
+-
|
|
|
+- if (content == CAIRO_CONTENT_COLOR) {
|
|
|
+- alpha = D2D1_ALPHA_MODE_IGNORE;
|
|
|
+- } else {
|
|
|
+- alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- size.width = sizePixels.width * dpiX;
|
|
|
+- size.height = sizePixels.height * dpiY;
|
|
|
+- D2D1_BITMAP_PROPERTIES bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- alpha));
|
|
|
+-
|
|
|
+- if (sizePixels.width < 1) {
|
|
|
+- sizePixels.width = 1;
|
|
|
+- }
|
|
|
+- if (sizePixels.height < 1) {
|
|
|
+- sizePixels.height = 1;
|
|
|
+- }
|
|
|
+- RefPtr<IDXGISurface> oldDxgiSurface;
|
|
|
+- d2dsurf->surface->QueryInterface(&oldDxgiSurface);
|
|
|
+- DXGI_SURFACE_DESC origDesc;
|
|
|
+-
|
|
|
+- oldDxgiSurface->GetDesc(&origDesc);
|
|
|
+-
|
|
|
+- CD3D10_TEXTURE2D_DESC desc(origDesc.Format,
|
|
|
+- sizePixels.width,
|
|
|
+- sizePixels.height);
|
|
|
+-
|
|
|
+- if (content == CAIRO_CONTENT_ALPHA) {
|
|
|
+- desc.Format = DXGI_FORMAT_A8_UNORM;
|
|
|
+- }
|
|
|
+-
|
|
|
+- desc.MipLevels = 1;
|
|
|
+- desc.Usage = D3D10_USAGE_DEFAULT;
|
|
|
+- desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
|
|
+-
|
|
|
+- /* CreateTexture2D does not support D3D10_RESOURCE_MISC_GDI_COMPATIBLE with DXGI_FORMAT_A8_UNORM */
|
|
|
+- if (desc.Format != DXGI_FORMAT_A8_UNORM)
|
|
|
+- desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> texture;
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+-
|
|
|
+- D2D1_RENDER_TARGET_USAGE usage = (desc.MiscFlags & D3D10_RESOURCE_MISC_GDI_COMPATIBLE) ?
|
|
|
+- D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE
|
|
|
+- : D2D1_RENDER_TARGET_USAGE_NONE;
|
|
|
+-
|
|
|
+- hr = d2dsurf->device->mD3D10Device->CreateTexture2D(&desc, NULL, &texture);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATESIMILAR;
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->surface = texture;
|
|
|
+-
|
|
|
+- // Create the DXGI surface.
|
|
|
+- hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATESIMILAR;
|
|
|
+- }
|
|
|
+-
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
|
|
+- D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- alpha),
|
|
|
+- dpiX,
|
|
|
+- dpiY,
|
|
|
+- usage),
|
|
|
+- &newSurf->rt);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATESIMILAR;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (desc.Format != DXGI_FORMAT_A8_UNORM) {
|
|
|
+- /* For some reason creation of shared bitmaps for A8 UNORM surfaces
|
|
|
+- * doesn't work even though the documentation suggests it does. The
|
|
|
+- * function will return an error if we try */
|
|
|
+- hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
|
|
|
+- dxgiSurface,
|
|
|
+- &bitProps,
|
|
|
+- &newSurf->surfaceBitmap);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATESIMILAR;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
|
|
+-
|
|
|
+- _d2d_clear_surface(newSurf);
|
|
|
+-
|
|
|
+- _cairo_d2d_surface_init(newSurf, d2dsurf->device, _cairo_format_from_content(content));
|
|
|
+-
|
|
|
+- return reinterpret_cast<cairo_surface_t*>(newSurf);
|
|
|
+-
|
|
|
+-FAIL_CREATESIMILAR:
|
|
|
+- /** Ensure we call our surfaces desctructor */
|
|
|
+- newSurf->~cairo_d2d_surface_t();
|
|
|
+- free(newSurf);
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_finish(void *surface)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- d2dsurf->device->mVRAMUsage -= _cairo_d2d_compute_surface_mem_size(d2dsurf);
|
|
|
+- if (d2dsurf->bufferTexture) {
|
|
|
+- d2dsurf->device->mVRAMUsage -= _cairo_d2d_compute_surface_mem_size(d2dsurf);
|
|
|
+- }
|
|
|
+-
|
|
|
+- reset_clip(d2dsurf);
|
|
|
+-
|
|
|
+- // We need to release the device after calling the constructor, since the
|
|
|
+- // device destruction may release the D3D/D2D libraries.
|
|
|
+- cairo_device_t *device = &d2dsurf->device->base;
|
|
|
+- d2dsurf->~cairo_d2d_surface_t();
|
|
|
+- cairo_release_device(device);
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/* The input types for src and dst don't match because in our particular use case, copying from a texture,
|
|
|
+- * those types don't match. */
|
|
|
+-static void
|
|
|
+-_copy_data_to_different_stride(unsigned char *dst, int dst_stride, void *src, UINT src_stride, int height)
|
|
|
+-{
|
|
|
+-
|
|
|
+- unsigned char *src_p = (unsigned char *)src;
|
|
|
+- int min_stride = MIN(dst_stride, src_stride);
|
|
|
+- while (height) {
|
|
|
+- memcpy(dst, src_p, min_stride);
|
|
|
+- height--;
|
|
|
+- dst += dst_stride;
|
|
|
+- src_p += src_stride;
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_acquire_source_image(void *abstract_surface,
|
|
|
+- cairo_image_surface_t **image_out_ret,
|
|
|
+- void **image_extra)
|
|
|
+-{
|
|
|
+- cairo_surface_t *image_out;
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
|
|
|
+- _cairo_d2d_flush(d2dsurf);
|
|
|
+-
|
|
|
+- HRESULT hr;
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> softTexture;
|
|
|
+-
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- d2dsurf->surface->QueryInterface(&dxgiSurface);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+-
|
|
|
+- dxgiSurface->GetDesc(&desc);
|
|
|
+-
|
|
|
+- CD3D10_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height);
|
|
|
+-
|
|
|
+- /**
|
|
|
+- * We can't actually map our backing store texture, so we create one in CPU memory, and then
|
|
|
+- * tell D3D to copy the data from our surface there, readback is expensive, we -never-
|
|
|
+- * -ever- want this to happen.
|
|
|
+- */
|
|
|
+- softDesc.MipLevels = 1;
|
|
|
+- softDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE | D3D10_CPU_ACCESS_READ;
|
|
|
+- softDesc.Usage = D3D10_USAGE_STAGING;
|
|
|
+- softDesc.BindFlags = 0;
|
|
|
+- hr = d2dsurf->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &softTexture);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return _cairo_error(CAIRO_STATUS_NO_MEMORY);
|
|
|
+- }
|
|
|
+-
|
|
|
+- d2dsurf->device->mD3D10Device->CopyResource(softTexture, d2dsurf->surface);
|
|
|
+-
|
|
|
+- D3D10_MAPPED_TEXTURE2D data;
|
|
|
+- hr = softTexture->Map(0, D3D10_MAP_READ_WRITE, 0, &data);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return _cairo_error(CAIRO_STATUS_NO_DEVICE);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (_cairo_valid_stride_alignment(data.RowPitch)) {
|
|
|
+- image_out = cairo_image_surface_create_for_data((unsigned char*)data.pData,
|
|
|
+- d2dsurf->format,
|
|
|
+- size.width,
|
|
|
+- size.height,
|
|
|
+- data.RowPitch);
|
|
|
+- } else {
|
|
|
+- /* Slow path used when the stride doesn't match our requirements.
|
|
|
+- * This is possible on at least the Intel driver 8.15.10.2302.
|
|
|
+- *
|
|
|
+- * Create a new image surface and copy our data into it */
|
|
|
+- image_out = cairo_image_surface_create(d2dsurf->format,
|
|
|
+- size.width,
|
|
|
+- size.height);
|
|
|
+- _copy_data_to_different_stride(cairo_image_surface_get_data(image_out),
|
|
|
+- cairo_image_surface_get_stride(image_out),
|
|
|
+- data.pData,
|
|
|
+- data.RowPitch,
|
|
|
+- size.height);
|
|
|
+-
|
|
|
+- }
|
|
|
+- /* these are the only surface statuses we expect */
|
|
|
+- assert(cairo_surface_status(image_out) == CAIRO_STATUS_SUCCESS ||
|
|
|
+- cairo_surface_status(image_out) == CAIRO_STATUS_NO_MEMORY);
|
|
|
+-
|
|
|
+- *image_extra = softTexture.forget().drop();
|
|
|
+- *image_out_ret = (cairo_image_surface_t*)image_out;
|
|
|
+-
|
|
|
+- return cairo_surface_status(image_out);
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_release_source_image(void *abstract_surface,
|
|
|
+- cairo_image_surface_t *image,
|
|
|
+- void *image_extra)
|
|
|
+-{
|
|
|
+- if (((cairo_surface_t*)abstract_surface)->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_surface_destroy(&image->base);
|
|
|
+- ID3D10Texture2D *softTexture = (ID3D10Texture2D*)image_extra;
|
|
|
+-
|
|
|
+- softTexture->Unmap(0);
|
|
|
+- softTexture->Release();
|
|
|
+- softTexture = NULL;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_acquire_dest_image(void *abstract_surface,
|
|
|
+- cairo_rectangle_int_t *interest_rect,
|
|
|
+- cairo_image_surface_t **image_out,
|
|
|
+- cairo_rectangle_int_t *image_rect,
|
|
|
+- void **image_extra)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
|
|
|
+- _cairo_d2d_flush(d2dsurf);
|
|
|
+-
|
|
|
+- HRESULT hr;
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> softTexture;
|
|
|
+-
|
|
|
+-
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- d2dsurf->surface->QueryInterface(&dxgiSurface);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+-
|
|
|
+- dxgiSurface->GetDesc(&desc);
|
|
|
+-
|
|
|
+- CD3D10_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height);
|
|
|
+-
|
|
|
+- image_rect->width = desc.Width;
|
|
|
+- image_rect->height = desc.Height;
|
|
|
+- image_rect->x = image_rect->y = 0;
|
|
|
+-
|
|
|
+- softDesc.MipLevels = 1;
|
|
|
+- softDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE | D3D10_CPU_ACCESS_READ;
|
|
|
+- softDesc.Usage = D3D10_USAGE_STAGING;
|
|
|
+- softDesc.BindFlags = 0;
|
|
|
+- hr = d2dsurf->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &softTexture);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return _cairo_error(CAIRO_STATUS_NO_MEMORY);
|
|
|
+- }
|
|
|
+- d2dsurf->device->mD3D10Device->CopyResource(softTexture, d2dsurf->surface);
|
|
|
+-
|
|
|
+- D3D10_MAPPED_TEXTURE2D data;
|
|
|
+- hr = softTexture->Map(0, D3D10_MAP_READ_WRITE, 0, &data);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return _cairo_error(CAIRO_STATUS_NO_DEVICE);
|
|
|
+- }
|
|
|
+- *image_out =
|
|
|
+- (cairo_image_surface_t*)cairo_image_surface_create_for_data((unsigned char*)data.pData,
|
|
|
+- _cairo_format_from_content(d2dsurf->base.content),
|
|
|
+- size.width,
|
|
|
+- size.height,
|
|
|
+- data.RowPitch);
|
|
|
+- *image_extra = softTexture.forget().drop();
|
|
|
+-
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static void
|
|
|
+-_cairo_d2d_release_dest_image(void *abstract_surface,
|
|
|
+- cairo_rectangle_int_t *interest_rect,
|
|
|
+- cairo_image_surface_t *image,
|
|
|
+- cairo_rectangle_int_t *image_rect,
|
|
|
+- void *image_extra)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
|
|
|
+-
|
|
|
+- ID3D10Texture2D *softTexture = (ID3D10Texture2D*)image_extra;
|
|
|
+- D2D1_POINT_2U point;
|
|
|
+- point.x = 0;
|
|
|
+- point.y = 0;
|
|
|
+- D2D1_RECT_U rect;
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+- rect.left = rect.top = 0;
|
|
|
+- rect.right = size.width;
|
|
|
+- rect.bottom = size.height;
|
|
|
+-
|
|
|
+- cairo_surface_destroy(&image->base);
|
|
|
+-
|
|
|
+- softTexture->Unmap(0);
|
|
|
+- d2dsurf->device->mD3D10Device->CopyResource(d2dsurf->surface, softTexture);
|
|
|
+- softTexture->Release();
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-static cairo_status_t
|
|
|
+-_cairo_d2d_flush(void *surface)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- if (d2dsurf->isDrawing) {
|
|
|
+- reset_clip(d2dsurf);
|
|
|
+- HRESULT hr = d2dsurf->rt->EndDraw();
|
|
|
+- d2dsurf->isDrawing = false;
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_copy_surface(cairo_d2d_surface_t *dst,
|
|
|
+- cairo_d2d_surface_t *src,
|
|
|
+- cairo_point_int_t *translation,
|
|
|
+- cairo_region_t *region)
|
|
|
+-{
|
|
|
+- RefPtr<IDXGISurface> dstSurface;
|
|
|
+- dst->surface->QueryInterface(&dstSurface);
|
|
|
+- RefPtr<IDXGISurface> srcSurface;
|
|
|
+- src->surface->QueryInterface(&srcSurface);
|
|
|
+- DXGI_SURFACE_DESC srcDesc, dstDesc;
|
|
|
+-
|
|
|
+- srcSurface->GetDesc(&srcDesc);
|
|
|
+- dstSurface->GetDesc(&dstDesc);
|
|
|
+-
|
|
|
+- cairo_rectangle_int_t clip_rect;
|
|
|
+- clip_rect.x = 0;
|
|
|
+- clip_rect.y = 0;
|
|
|
+- clip_rect.width = dstDesc.Width;
|
|
|
+- clip_rect.height = dstDesc.Height;
|
|
|
+-
|
|
|
+- cairo_int_status_t rv = CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-
|
|
|
+- _cairo_d2d_flush(dst);
|
|
|
+- ID3D10Resource *srcResource = src->surface;
|
|
|
+- if (src->surface.get() == dst->surface.get()) {
|
|
|
+- // Self-copy
|
|
|
+- srcResource = _cairo_d2d_get_buffer_texture(dst);
|
|
|
+- src->device->mD3D10Device->CopyResource(srcResource, src->surface);
|
|
|
+- } else {
|
|
|
+- // Need to flush the source too if it's a different surface.
|
|
|
+- _cairo_d2d_flush(src);
|
|
|
+- }
|
|
|
+-
|
|
|
+- // One copy for each rectangle in the final clipping region.
|
|
|
+- for (int i = 0; i < cairo_region_num_rectangles(region); i++) {
|
|
|
+- D3D10_BOX rect;
|
|
|
+- cairo_rectangle_int_t area_to_copy;
|
|
|
+-
|
|
|
+- cairo_region_get_rectangle(region, i, &area_to_copy);
|
|
|
+-
|
|
|
+- cairo_rectangle_int_t transformed_rect = { area_to_copy.x + translation->x,
|
|
|
+- area_to_copy.y + translation->y,
|
|
|
+- area_to_copy.width, area_to_copy.height };
|
|
|
+- cairo_rectangle_int_t surface_rect = { 0, 0,
|
|
|
+- static_cast<int>(srcDesc.Width),
|
|
|
+- static_cast<int>(srcDesc.Height) };
|
|
|
+-
|
|
|
+-
|
|
|
+- if (!_cairo_rectangle_contains(&surface_rect, &transformed_rect)) {
|
|
|
+- /* We cannot do any sort of extend, in the future a little bit of extra code could
|
|
|
+- * allow us to support EXTEND_NONE.
|
|
|
+- */
|
|
|
+- rv = CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- rect.front = 0;
|
|
|
+- rect.back = 1;
|
|
|
+- rect.left = transformed_rect.x;
|
|
|
+- rect.top = transformed_rect.y;
|
|
|
+- rect.right = transformed_rect.x + transformed_rect.width;
|
|
|
+- rect.bottom = transformed_rect.y + transformed_rect.height;
|
|
|
+-
|
|
|
+- src->device->mD3D10Device->CopySubresourceRegion(dst->surface,
|
|
|
+- 0,
|
|
|
+- area_to_copy.x,
|
|
|
+- area_to_copy.y,
|
|
|
+- 0,
|
|
|
+- srcResource,
|
|
|
+- 0,
|
|
|
+- &rect);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_blend_surface(cairo_d2d_surface_t *dst,
|
|
|
+- cairo_d2d_surface_t *src,
|
|
|
+- const cairo_matrix_t *transform,
|
|
|
+- cairo_box_t *box,
|
|
|
+- cairo_clip_t *clip,
|
|
|
+- cairo_filter_t filter,
|
|
|
+- float opacity)
|
|
|
+-{
|
|
|
+- if (dst == src) {
|
|
|
+- // We cannot do self-blend.
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- cairo_int_status_t rv = CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-
|
|
|
+- _begin_draw_state(dst);
|
|
|
+- _cairo_d2d_set_clip(dst, clip);
|
|
|
+- _cairo_d2d_flush(src);
|
|
|
+- D2D1_SIZE_U sourceSize = src->surfaceBitmap->GetPixelSize();
|
|
|
+-
|
|
|
+-
|
|
|
+- double x1, x2, y1, y2;
|
|
|
+- if (box) {
|
|
|
+- _cairo_box_to_doubles(box, &x1, &y1, &x2, &y2);
|
|
|
+- } else {
|
|
|
+- x1 = y1 = 0;
|
|
|
+- x2 = dst->rt->GetSize().width;
|
|
|
+- y2 = dst->rt->GetSize().height;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (clip) {
|
|
|
+- const cairo_rectangle_int_t *clipExtent = _cairo_clip_get_extents(clip);
|
|
|
+- x1 = MAX(x1, clipExtent->x);
|
|
|
+- x2 = MIN(x2, clipExtent->x + clipExtent->width);
|
|
|
+- y1 = MAX(y1, clipExtent->y);
|
|
|
+- y2 = MIN(y2, clipExtent->y + clipExtent->height);
|
|
|
+- }
|
|
|
+-
|
|
|
+- // We should be in drawing state for this.
|
|
|
+- _begin_draw_state(dst);
|
|
|
+- _cairo_d2d_set_clip (dst, clip);
|
|
|
+- D2D1_RECT_F rectSrc;
|
|
|
+- rectSrc.left = (float)(x1 * transform->xx + transform->x0);
|
|
|
+- rectSrc.top = (float)(y1 * transform->yy + transform->y0);
|
|
|
+- rectSrc.right = (float)(x2 * transform->xx + transform->x0);
|
|
|
+- rectSrc.bottom = (float)(y2 * transform->yy + transform->y0);
|
|
|
+-
|
|
|
+- if (rectSrc.left < 0 || rectSrc.top < 0 || rectSrc.right < 0 || rectSrc.bottom < 0 ||
|
|
|
+- rectSrc.right > sourceSize.width || rectSrc.bottom > sourceSize.height ||
|
|
|
+- rectSrc.left > sourceSize.width || rectSrc.top > sourceSize.height) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_RECT_F rectDst;
|
|
|
+- rectDst.left = (float)x1;
|
|
|
+- rectDst.top = (float)y1;
|
|
|
+- rectDst.right = (float)x2;
|
|
|
+- rectDst.bottom = (float)y2;
|
|
|
+-
|
|
|
+- // Bug 599658 - if the src rect is inverted in either axis D2D is fine with
|
|
|
+- // this but it does not actually invert the bitmap. This is an easy way
|
|
|
+- // of doing that.
|
|
|
+- D2D1_MATRIX_3X2_F matrix = D2D1::IdentityMatrix();
|
|
|
+- bool needsTransform = false;
|
|
|
+- if (rectSrc.left > rectSrc.right) {
|
|
|
+- rectDst.left = -rectDst.left;
|
|
|
+- rectDst.right = -rectDst.right;
|
|
|
+- matrix._11 = -1.0;
|
|
|
+- needsTransform = true;
|
|
|
+- }
|
|
|
+- if (rectSrc.top > rectSrc.bottom) {
|
|
|
+- rectDst.top = -rectDst.top;
|
|
|
+- rectDst.bottom = -rectDst.bottom;
|
|
|
+- matrix._22 = -1.0;
|
|
|
+- needsTransform = true;
|
|
|
+- }
|
|
|
+-
|
|
|
+- _cairo_d2d_add_dependent_surface(src, dst);
|
|
|
+-
|
|
|
+- D2D1_BITMAP_INTERPOLATION_MODE interpMode =
|
|
|
+- D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
|
|
|
+-
|
|
|
+- if (needsTransform) {
|
|
|
+- dst->rt->SetTransform(matrix);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (filter == CAIRO_FILTER_NEAREST) {
|
|
|
+- interpMode = D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
|
|
|
+- }
|
|
|
+-
|
|
|
+- dst->rt->DrawBitmap(src->surfaceBitmap,
|
|
|
+- rectDst,
|
|
|
+- opacity,
|
|
|
+- interpMode,
|
|
|
+- rectSrc);
|
|
|
+- if (needsTransform) {
|
|
|
+- dst->rt->SetTransform(D2D1::IdentityMatrix());
|
|
|
+- }
|
|
|
+-
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-/**
|
|
|
+- * This function will text if we can use GPU mem cpy to execute an operation with
|
|
|
+- * a surface pattern. If box is NULL it will operate on the entire dst surface.
|
|
|
+- */
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_try_fastblit(cairo_d2d_surface_t *dst,
|
|
|
+- cairo_surface_t *src,
|
|
|
+- cairo_box_t *box,
|
|
|
+- const cairo_matrix_t *matrix,
|
|
|
+- cairo_clip_t *clip,
|
|
|
+- cairo_operator_t op,
|
|
|
+- cairo_filter_t filter,
|
|
|
+- float opacity = 1.0f)
|
|
|
+-{
|
|
|
+- if (op == CAIRO_OPERATOR_OVER && src->content == CAIRO_CONTENT_COLOR) {
|
|
|
+- op = CAIRO_OPERATOR_SOURCE;
|
|
|
+- }
|
|
|
+- if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* For now we do only D2D sources */
|
|
|
+- if (src->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsrc = reinterpret_cast<cairo_d2d_surface_t*>(src);
|
|
|
+- if (op == CAIRO_OPERATOR_OVER && matrix->xy == 0 && matrix->yx == 0) {
|
|
|
+- return _cairo_d2d_blend_surface(dst, d2dsrc, matrix, box, clip, filter, opacity);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_OVER || opacity != 1.0f) {
|
|
|
+- // Past this point we will never get into a situation where we can
|
|
|
+- // support OVER.
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_point_int_t translation;
|
|
|
+- if ((box && !box_is_integer(box)) ||
|
|
|
+- !_cairo_matrix_is_integer_translation(matrix, &translation.x, &translation.y)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_rectangle_int_t rect;
|
|
|
+- if (box) {
|
|
|
+- _cairo_box_round_to_rectangle(box, &rect);
|
|
|
+- } else {
|
|
|
+- rect.x = rect.y = 0;
|
|
|
+- rect.width = dst->rt->GetPixelSize().width;
|
|
|
+- rect.height = dst->rt->GetPixelSize().height;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (d2dsrc->device != dst->device) {
|
|
|
+- // This doesn't work between different devices.
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- /* Region we need to clip this operation to */
|
|
|
+- cairo_region_t *clipping_region = NULL;
|
|
|
+- cairo_region_t *region;
|
|
|
+- cairo_region_auto_ptr region_ptr;
|
|
|
+-
|
|
|
+- if (clip) {
|
|
|
+- _cairo_clip_get_region(clip, &clipping_region);
|
|
|
+-
|
|
|
+- if (!clipping_region) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- region = cairo_region_copy(clipping_region);
|
|
|
+- region_ptr.set(region);
|
|
|
+-
|
|
|
+- cairo_region_intersect_rectangle(region, &rect);
|
|
|
+-
|
|
|
+- if (cairo_region_is_empty(region)) {
|
|
|
+- // Nothing to do.
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- region = cairo_region_create_rectangle(&rect);
|
|
|
+- region_ptr.set(region);
|
|
|
+-
|
|
|
+- // Areas outside of the surface do not matter.
|
|
|
+- cairo_rectangle_int_t surface_rect = { 0, 0,
|
|
|
+- static_cast<int>(dst->rt->GetPixelSize().width),
|
|
|
+- static_cast<int>(dst->rt->GetPixelSize().height) };
|
|
|
+- cairo_region_intersect_rectangle(region, &surface_rect);
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_int_status_t rv = _cairo_d2d_copy_surface(dst, d2dsrc, &translation, region);
|
|
|
+-
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static RefPtr<ID2D1RenderTarget>
|
|
|
+-_cairo_d2d_get_temp_rt(cairo_d2d_surface_t *surf, cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- RefPtr<ID3D10Texture2D> texture = _cairo_d2d_get_buffer_texture(surf);
|
|
|
+- RefPtr<ID2D1RenderTarget> new_rt;
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- texture->QueryInterface(&dxgiSurface);
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- _cairo_d2d_flush(surf);
|
|
|
+-
|
|
|
+- if (!surf) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_RENDER_TARGET_PROPERTIES props =
|
|
|
+- D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
|
|
+- props,
|
|
|
+- &new_rt);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- new_rt->BeginDraw();
|
|
|
+- new_rt->Clear(D2D1::ColorF(0, 0));
|
|
|
+-
|
|
|
+- // Since this is a fresh surface there's no point in doing clever things to
|
|
|
+- // keep the clip path around until a certain depth. So we just do a straight-
|
|
|
+- // forward push of all clip paths in the tree, similar to what the normal
|
|
|
+- // clip code does, but a little less clever.
|
|
|
+- if (clip) {
|
|
|
+- cairo_clip_path_t *path = clip->path;
|
|
|
+- while (path) {
|
|
|
+- cairo_box_t clip_box;
|
|
|
+- if (_cairo_path_fixed_is_box(&path->path, &clip_box)) {
|
|
|
+- // If this does not have a region it could be none-pixel aligned.
|
|
|
+- D2D1_ANTIALIAS_MODE aaMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
|
|
|
+- if (box_is_integer(&clip_box)) {
|
|
|
+- aaMode = D2D1_ANTIALIAS_MODE_ALIASED;
|
|
|
+- }
|
|
|
+- new_rt->PushAxisAlignedClip(D2D1::RectF(_cairo_fixed_to_float(clip_box.p1.x),
|
|
|
+- _cairo_fixed_to_float(clip_box.p1.y),
|
|
|
+- _cairo_fixed_to_float(clip_box.p2.x),
|
|
|
+- _cairo_fixed_to_float(clip_box.p2.y)),
|
|
|
+- aaMode);
|
|
|
+- } else {
|
|
|
+- HRESULT hr;
|
|
|
+- RefPtr<ID2D1PathGeometry> geom = _cairo_d2d_create_path_geometry_for_path (&path->path,
|
|
|
+- path->fill_rule,
|
|
|
+- D2D1_FIGURE_BEGIN_FILLED);
|
|
|
+- RefPtr<ID2D1Layer> layer;
|
|
|
+-
|
|
|
+- hr = new_rt->CreateLayer (&layer);
|
|
|
+-
|
|
|
+- D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
|
|
|
+-
|
|
|
+- new_rt->PushLayer(D2D1::LayerParameters(
|
|
|
+- D2D1::InfiniteRect(),
|
|
|
+- geom,
|
|
|
+- D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
|
|
|
+- D2D1::IdentityMatrix(),
|
|
|
+- 1.0,
|
|
|
+- 0,
|
|
|
+- options),
|
|
|
+- layer);
|
|
|
+- }
|
|
|
+- path = path->prev;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- return new_rt;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_blend_temp_surface(cairo_d2d_surface_t *surf, cairo_operator_t op, ID2D1RenderTarget *rt, cairo_clip_t *clip, const cairo_rectangle_int_t *bounds = NULL)
|
|
|
+-{
|
|
|
+- _cairo_d2d_flush_dependent_surfaces(surf);
|
|
|
+-
|
|
|
+- int numPaths = 0;
|
|
|
+- if (clip) {
|
|
|
+- cairo_clip_path_t *path = clip->path;
|
|
|
+- while (path) {
|
|
|
+- numPaths++;
|
|
|
+- path = path->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_clip_path_t **paths = new cairo_clip_path_t*[numPaths];
|
|
|
+-
|
|
|
+- numPaths = 0;
|
|
|
+- path = clip->path;
|
|
|
+- while (path) {
|
|
|
+- paths[numPaths++] = path;
|
|
|
+- path = path->prev;
|
|
|
+- }
|
|
|
+-
|
|
|
+- for (int i = numPaths - 1; i >= 0; i--) {
|
|
|
+- if (paths[i]->flags & CAIRO_CLIP_PATH_IS_BOX) {
|
|
|
+- rt->PopAxisAlignedClip();
|
|
|
+- } else {
|
|
|
+- rt->PopLayer();
|
|
|
+- }
|
|
|
+- }
|
|
|
+- delete [] paths;
|
|
|
+- }
|
|
|
+- rt->EndDraw();
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> srcTexture = _cairo_d2d_get_buffer_texture(surf);
|
|
|
+- RefPtr<ID3D10Texture2D> dstTexture;
|
|
|
+-
|
|
|
+- surf->surface->QueryInterface(&dstTexture);
|
|
|
+- ID3D10Device *device = surf->device->mD3D10Device;
|
|
|
+-
|
|
|
+- if (!surf->buffer_rt_view) {
|
|
|
+- hr = device->CreateRenderTargetView(dstTexture, NULL, &surf->buffer_rt_view);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!surf->buffer_sr_view) {
|
|
|
+- hr = device->CreateShaderResourceView(srcTexture, NULL, &surf->buffer_sr_view);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- status = _cairo_d2d_set_operator(surf->device, op);
|
|
|
+-
|
|
|
+- if (unlikely(status)) {
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D3D10_TEXTURE2D_DESC tDesc;
|
|
|
+- dstTexture->GetDesc(&tDesc);
|
|
|
+- D3D10_VIEWPORT vp;
|
|
|
+- vp.Height = tDesc.Height;
|
|
|
+- vp.MinDepth = 0;
|
|
|
+- vp.MaxDepth = 1.0;
|
|
|
+- vp.TopLeftX = 0;
|
|
|
+- vp.TopLeftY = 0;
|
|
|
+- vp.Width = tDesc.Width;
|
|
|
+- device->RSSetViewports(1, &vp);
|
|
|
+-
|
|
|
+- ID3D10Effect *effect = surf->device->mSampleEffect;
|
|
|
+-
|
|
|
+- ID3D10RenderTargetView *rtViewPtr = surf->buffer_rt_view;
|
|
|
+- device->OMSetRenderTargets(1, &rtViewPtr, 0);
|
|
|
+- ID3D10EffectVectorVariable *quadDesc = effect->GetVariableByName("QuadDesc")->AsVector();
|
|
|
+- ID3D10EffectVectorVariable *texCoords = effect->GetVariableByName("TexCoords")->AsVector();
|
|
|
+-
|
|
|
+- float quadDescVal[] = { -1.0f, 1.0f, 2.0f, -2.0f };
|
|
|
+- float texCoordsVal[] = { 0.0, 0.0, 1.0f, 1.0f };
|
|
|
+- if (bounds && _cairo_operator_bounded_by_mask(op)) {
|
|
|
+- quadDescVal[0] = -1.0f + ((float)bounds->x / (float)tDesc.Width) * 2.0f;
|
|
|
+- quadDescVal[1] = 1.0f - ((float)bounds->y / (float)tDesc.Height) * 2.0f;
|
|
|
+- quadDescVal[2] = ((float)bounds->width / (float)tDesc.Width) * 2.0f;
|
|
|
+- quadDescVal[3] = -((float)bounds->height / (float)tDesc.Height) * 2.0f;
|
|
|
+- texCoordsVal[0] = (float)bounds->x / (float)tDesc.Width;
|
|
|
+- texCoordsVal[1] = (float)bounds->y / (float)tDesc.Height;
|
|
|
+- texCoordsVal[2] = (float)bounds->width / (float)tDesc.Width;
|
|
|
+- texCoordsVal[3] = (float)bounds->height / (float)tDesc.Height;
|
|
|
+- }
|
|
|
+- quadDesc->SetFloatVector(quadDescVal);
|
|
|
+- texCoords->SetFloatVector(texCoordsVal);
|
|
|
+-
|
|
|
+- _cairo_d2d_setup_for_blend(surf->device);
|
|
|
+- ID3D10EffectTechnique *technique = effect->GetTechniqueByName("SampleTexture");
|
|
|
+- technique->GetPassByIndex(0)->Apply(0);
|
|
|
+-
|
|
|
+- ID3D10ShaderResourceView *srViewPtr = surf->buffer_sr_view;
|
|
|
+- device->PSSetShaderResources(0, 1, &srViewPtr);
|
|
|
+-
|
|
|
+- device->Draw(4, 0);
|
|
|
+-
|
|
|
+-#ifdef DEBUG
|
|
|
+- // Quiet down some info messages from D3D10 debug layer
|
|
|
+- srViewPtr = NULL;
|
|
|
+- device->PSSetShaderResources(0, 1, &srViewPtr);
|
|
|
+- rtViewPtr = NULL;
|
|
|
+- device->OMSetRenderTargets(1, &rtViewPtr, 0);
|
|
|
+-#endif
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_paint(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- op = _cairo_d2d_simplify_operator(op, source);
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_SOURCE) {
|
|
|
+- if (!clip) {
|
|
|
+- _cairo_d2d_clear(d2dsurf, NULL);
|
|
|
+- op = CAIRO_OPERATOR_OVER;
|
|
|
+- } else {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_CLEAR) {
|
|
|
+- return _cairo_d2d_clear(d2dsurf, clip);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
+- const cairo_surface_pattern_t *surf_pattern =
|
|
|
+- reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
|
|
+-
|
|
|
+- status = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
|
|
|
+- NULL, &source->matrix, clip,
|
|
|
+- op, source->filter);
|
|
|
+-
|
|
|
+- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- if (op != CAIRO_OPERATOR_OVER) {
|
|
|
+-#endif
|
|
|
+- target_rt = _cairo_d2d_get_temp_rt(d2dsurf, clip);
|
|
|
+- if (!target_rt) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- } else {
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, clip);
|
|
|
+-
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL,
|
|
|
+- source);
|
|
|
+-
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_SIZE_F size = target_rt->GetSize();
|
|
|
+- target_rt->FillRectangle(D2D1::RectF((FLOAT)0,
|
|
|
+- (FLOAT)0,
|
|
|
+- (FLOAT)size.width,
|
|
|
+- (FLOAT)size.height),
|
|
|
+- brush);
|
|
|
+-
|
|
|
+- if (target_rt.get() != d2dsurf->rt.get()) {
|
|
|
+- return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_mask(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- const cairo_pattern_t *mask,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- cairo_rectangle_int_t extents;
|
|
|
+-
|
|
|
+- cairo_clip_t *actual_clip = clip;
|
|
|
+- cairo_clip_t temporary_clip;
|
|
|
+-
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- status = (cairo_int_status_t)_cairo_surface_mask_extents (&d2dsurf->base,
|
|
|
+- op, source,
|
|
|
+- mask,
|
|
|
+- clip, &extents);
|
|
|
+- if (unlikely (status))
|
|
|
+- return status;
|
|
|
+-
|
|
|
+- bool isSolidAlphaMask = false;
|
|
|
+- float solidAlphaValue = 1.0f;
|
|
|
+-
|
|
|
+- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
|
|
|
+- cairo_solid_pattern_t *solidPattern =
|
|
|
+- (cairo_solid_pattern_t*)mask;
|
|
|
+- if (_cairo_color_get_content (&solidPattern->color) == CAIRO_CONTENT_ALPHA) {
|
|
|
+- isSolidAlphaMask = true;
|
|
|
+- solidAlphaValue = solidPattern->color.alpha;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_box_t box;
|
|
|
+- _cairo_box_from_rectangle(&box, &extents);
|
|
|
+-
|
|
|
+- if (clip && isSolidAlphaMask) {
|
|
|
+- // We do some work here to try and avoid pushing and popping clips for rectangular areas,
|
|
|
+- // if we do this fill rects will occur without rectangular clips being pushed and popped.
|
|
|
+- // This is faster for non-axis aligned clips in general and allows more efficient batching
|
|
|
+- // of the pop-clip calls.
|
|
|
+- int num_boxes = 1;
|
|
|
+- cairo_box_t box_stack;
|
|
|
+- cairo_box_t *boxes;
|
|
|
+- boxes = &box_stack;
|
|
|
+-
|
|
|
+- // This function assumes atleast a single box resides at 'boxes' and the
|
|
|
+- // amount of boxes that reside there are passed in under num_boxes.
|
|
|
+- status = _cairo_clip_get_boxes(clip, &boxes, &num_boxes);
|
|
|
+-
|
|
|
+- if (!status && num_boxes == 1) {
|
|
|
+- box.p1.x = MAX(box.p1.x, boxes->p1.x);
|
|
|
+- box.p2.x = MIN(box.p2.x, boxes->p2.x);
|
|
|
+- box.p1.y = MAX(box.p1.y, boxes->p1.y);
|
|
|
+- box.p2.y = MIN(box.p2.y, boxes->p2.y);
|
|
|
+-
|
|
|
+- if (clip->path != d2dsurf->clip.path) {
|
|
|
+- // If we have a clip set, but it's not the right one. We want to
|
|
|
+- // pop as much as we need to, to be sure the area affected by
|
|
|
+- // the operation is not clipped. To do this we set the clip path
|
|
|
+- // to the common ancestor of the currently set clip path and the
|
|
|
+- // clip path for this operation. This will cause
|
|
|
+- // _cairo_d2d_set_clip to pop to that common ancestor, but not
|
|
|
+- // needlessly push the additional clips we're trying to avoid.
|
|
|
+- temporary_clip.path = find_common_ancestor(clip->path, d2dsurf->clip.path);
|
|
|
+-
|
|
|
+- // We're not going to be using this down the line so it doesn't
|
|
|
+- // really matter what the value is. If all -was- clipped this
|
|
|
+- // call shouldn't even have reached the surface backend.
|
|
|
+- temporary_clip.all_clipped = FALSE;
|
|
|
+-
|
|
|
+- actual_clip = &temporary_clip;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (boxes != &box_stack) {
|
|
|
+- // If the function changed the boxes pointer, we need to free it.
|
|
|
+- free(boxes);
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (isSolidAlphaMask) {
|
|
|
+- if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
+- const cairo_surface_pattern_t *surf_pattern =
|
|
|
+- reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
|
|
+- cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf,
|
|
|
+- surf_pattern->surface,
|
|
|
+- &box,
|
|
|
+- &source->matrix,
|
|
|
+- clip,
|
|
|
+- op,
|
|
|
+- source->filter,
|
|
|
+- solidAlphaValue);
|
|
|
+- if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
+- return rv;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, source);
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- if (op != CAIRO_OPERATOR_OVER) {
|
|
|
+-#endif
|
|
|
+- target_rt = _cairo_d2d_get_temp_rt(d2dsurf, clip);
|
|
|
+- if (!target_rt) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- } else {
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+-
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, actual_clip);
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- D2D1_RECT_F rect = D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
|
|
|
+- _cairo_fixed_to_float(box.p1.y),
|
|
|
+- _cairo_fixed_to_float(box.p2.x),
|
|
|
+- _cairo_fixed_to_float(box.p2.y));
|
|
|
+-
|
|
|
+- if (isSolidAlphaMask) {
|
|
|
+- brush->SetOpacity(solidAlphaValue);
|
|
|
+- target_rt->FillRectangle(rect,
|
|
|
+- brush);
|
|
|
+- brush->SetOpacity(1.0);
|
|
|
+-
|
|
|
+- if (target_rt.get() != d2dsurf->rt.get()) {
|
|
|
+- return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip);
|
|
|
+- }
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL, mask, true);
|
|
|
+- if (!opacityBrush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!d2dsurf->maskLayer) {
|
|
|
+- d2dsurf->rt->CreateLayer(&d2dsurf->maskLayer);
|
|
|
+- }
|
|
|
+- target_rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(),
|
|
|
+- 0,
|
|
|
+- D2D1_ANTIALIAS_MODE_ALIASED,
|
|
|
+- D2D1::IdentityMatrix(),
|
|
|
+- 1.0,
|
|
|
+- opacityBrush),
|
|
|
+- d2dsurf->maskLayer);
|
|
|
+-
|
|
|
+- target_rt->FillRectangle(rect,
|
|
|
+- brush);
|
|
|
+- target_rt->PopLayer();
|
|
|
+-
|
|
|
+- if (target_rt.get() != d2dsurf->rt.get()) {
|
|
|
+- return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip);
|
|
|
+- }
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_stroke(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_path_fixed_t *path,
|
|
|
+- const cairo_stroke_style_t *style,
|
|
|
+- const cairo_matrix_t *ctm,
|
|
|
+- const cairo_matrix_t *ctm_inverse,
|
|
|
+- double tolerance,
|
|
|
+- cairo_antialias_t antialias,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- op = _cairo_d2d_simplify_operator(op, source);
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_SOURCE) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- if (op != CAIRO_OPERATOR_OVER) {
|
|
|
+-#endif
|
|
|
+- target_rt = _cairo_d2d_get_temp_rt(d2dsurf, clip);
|
|
|
+- if (!target_rt) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- } else {
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, clip);
|
|
|
+-
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- if (antialias == CAIRO_ANTIALIAS_NONE) {
|
|
|
+- target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
+- } else {
|
|
|
+- target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
|
+- }
|
|
|
+- RefPtr<ID2D1StrokeStyle> strokeStyle = _cairo_d2d_create_strokestyle_for_stroke_style(style);
|
|
|
+-
|
|
|
+- if (!strokeStyle) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path,
|
|
|
+- CAIRO_FILL_RULE_WINDING,
|
|
|
+- D2D1_FIGURE_BEGIN_FILLED);
|
|
|
+-
|
|
|
+- bool transformed = true;
|
|
|
+-
|
|
|
+- if (_cairo_matrix_is_identity(ctm)) {
|
|
|
+- transformed = false;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, NULL,
|
|
|
+- source);
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1::Matrix3x2F mat;
|
|
|
+- if (transformed) {
|
|
|
+- // If we are transformed we will draw the geometry multiplied by the
|
|
|
+- // inverse transformation and apply the transform to our render target.
|
|
|
+- // This way the transformation will also be applied to the strokestyle.
|
|
|
+- mat = _cairo_d2d_matrix_from_matrix(ctm);
|
|
|
+- D2D1::Matrix3x2F inverse_mat = _cairo_d2d_invert_matrix(mat);
|
|
|
+-
|
|
|
+- RefPtr<ID2D1TransformedGeometry> trans_geom;
|
|
|
+- sD2DFactory->CreateTransformedGeometry(d2dpath, &inverse_mat, &trans_geom);
|
|
|
+-
|
|
|
+- // If we are setting a transform on the render target, we've multiplied
|
|
|
+- // the geometry by the inverse transform, we should also multiply the
|
|
|
+- // brush matrix by this inverse transform then to map the brush to the
|
|
|
+- // correct place.
|
|
|
+- D2D1_MATRIX_3X2_F brushMatrix;
|
|
|
+- brush->GetTransform(&brushMatrix);
|
|
|
+- brushMatrix = brushMatrix * inverse_mat;
|
|
|
+- brush->SetTransform(brushMatrix);
|
|
|
+- target_rt->SetTransform(mat);
|
|
|
+- d2dpath = trans_geom;
|
|
|
+- } else {
|
|
|
+- mat = D2D1::Matrix3x2F::Identity();
|
|
|
+- }
|
|
|
+-
|
|
|
+- target_rt->DrawGeometry(d2dpath, brush, (FLOAT)style->line_width, strokeStyle);
|
|
|
+-
|
|
|
+- if (transformed) {
|
|
|
+- target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (target_rt.get() != d2dsurf->rt.get()) {
|
|
|
+- D2D1_RECT_F bounds;
|
|
|
+- d2dpath->GetWidenedBounds((FLOAT)style->line_width, strokeStyle, mat, &bounds);
|
|
|
+- cairo_rectangle_int_t bound_rect;
|
|
|
+- _cairo_d2d_round_out_to_int_rect(&bound_rect, bounds.left, bounds.top, bounds.right, bounds.bottom);
|
|
|
+- return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bound_rect);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_fill(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_path_fixed_t *path,
|
|
|
+- cairo_fill_rule_t fill_rule,
|
|
|
+- double tolerance,
|
|
|
+- cairo_antialias_t antialias,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- cairo_box_t box;
|
|
|
+- bool is_box = _cairo_path_fixed_is_box(path, &box);
|
|
|
+-
|
|
|
+- if (is_box && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
|
|
|
+- const cairo_surface_pattern_t *surf_pattern =
|
|
|
+- reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
|
|
+- cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
|
|
|
+- &box, &source->matrix, clip, op,
|
|
|
+- source->filter);
|
|
|
+-
|
|
|
+- if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
+- return rv;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- op = _cairo_d2d_simplify_operator(op, source);
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_SOURCE) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_CLEAR) {
|
|
|
+- if (_cairo_path_fixed_is_box(path, &box)) {
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, clip);
|
|
|
+-
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+-
|
|
|
+- return _cairo_d2d_clear_box (d2dsurf, clip, &box);
|
|
|
+- } else {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1RenderTarget> target_rt = d2dsurf->rt;
|
|
|
+-
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- if (op != CAIRO_OPERATOR_OVER) {
|
|
|
+-#endif
|
|
|
+- target_rt = _cairo_d2d_get_temp_rt(d2dsurf, clip);
|
|
|
+- if (!target_rt) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- } else {
|
|
|
+- _begin_draw_state(d2dsurf);
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (d2dsurf, clip);
|
|
|
+-
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- if (antialias == CAIRO_ANTIALIAS_NONE) {
|
|
|
+- target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
|
|
+- } else {
|
|
|
+- target_rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (is_box) {
|
|
|
+- float x1 = _cairo_fixed_to_float(box.p1.x);
|
|
|
+- float y1 = _cairo_fixed_to_float(box.p1.y);
|
|
|
+- float x2 = _cairo_fixed_to_float(box.p2.x);
|
|
|
+- float y2 = _cairo_fixed_to_float(box.p2.y);
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
|
|
|
+- path, source);
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- target_rt->FillRectangle(D2D1::RectF(x1,
|
|
|
+- y1,
|
|
|
+- x2,
|
|
|
+- y2),
|
|
|
+- brush);
|
|
|
+- } else {
|
|
|
+- RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
|
|
|
+- path, source);
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- target_rt->FillGeometry(d2dpath, brush);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (target_rt.get() != d2dsurf->rt.get()) {
|
|
|
+- double x1, y1, x2, y2;
|
|
|
+- cairo_box_t box;
|
|
|
+- _cairo_path_fixed_extents (path, &box);
|
|
|
+- x1 = _cairo_fixed_to_double (box.p1.x);
|
|
|
+- y1 = _cairo_fixed_to_double (box.p1.y);
|
|
|
+- x2 = _cairo_fixed_to_double (box.p2.x);
|
|
|
+- y2 = _cairo_fixed_to_double (box.p2.y);
|
|
|
+- cairo_rectangle_int_t bounds;
|
|
|
+- _cairo_d2d_round_out_to_int_rect(&bounds, x1, y1, x2, y2);
|
|
|
+- return _cairo_d2d_blend_temp_surface(d2dsurf, op, target_rt, clip, &bounds);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_int_status_t
|
|
|
+-_cairo_dwrite_manual_show_glyphs_on_d2d_surface(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_solid_pattern_t *source,
|
|
|
+- cairo_glyph_t *glyphs,
|
|
|
+- int num_glyphs,
|
|
|
+- cairo_dwrite_scaled_font_t *scaled_font,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
|
|
|
+- if (!dwritesf->manual_show_glyphs_allowed) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->base.font_face);
|
|
|
+- cairo_d2d_surface_t *dst = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- BOOL transform = FALSE;
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- cairo_region_t *clip_region = NULL;
|
|
|
+-
|
|
|
+- // We can only draw axis and pixel aligned rectangular quads, this means we
|
|
|
+- // can only support clips which form regions, since the intersection with
|
|
|
+- // our text area will then always be a set of rectangular axis and pixel
|
|
|
+- // aligned quads.
|
|
|
+- if (clip) {
|
|
|
+- _cairo_clip_get_region(clip, &clip_region);
|
|
|
+- if (!clip_region) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!dst->isDrawing) {
|
|
|
+- _cairo_d2d_flush_dependent_surfaces(dst);
|
|
|
+- }
|
|
|
+-
|
|
|
+- _cairo_d2d_set_clip(dst, NULL);
|
|
|
+- dst->rt->Flush();
|
|
|
+-
|
|
|
+- AutoDWriteGlyphRun run;
|
|
|
+- _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, scaled_font, &run, &transform);
|
|
|
+-
|
|
|
+- RefPtr<IDWriteGlyphRunAnalysis> analysis;
|
|
|
+- DWRITE_MATRIX dwmat = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat);
|
|
|
+-
|
|
|
+- RefPtr<IDWriteRenderingParams> params;
|
|
|
+- dst->rt->GetTextRenderingParams(¶ms);
|
|
|
+-
|
|
|
+- DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
|
|
|
+- if (params) {
|
|
|
+- hr = dwriteff->dwriteface->GetRecommendedRenderingMode(
|
|
|
+- (FLOAT)scaled_font->base.font_matrix.yy,
|
|
|
+- 1.0f,
|
|
|
+- DWRITE_MEASURING_MODE_NATURAL,
|
|
|
+- params,
|
|
|
+- &renderMode);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- // this probably never happens, but let's play it safe
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_DEFAULT;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept.
|
|
|
+- switch (renderMode) {
|
|
|
+- case DWRITE_RENDERING_MODE_ALIASED:
|
|
|
+- // ClearType texture creation will fail in this mode, so bail out
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- case DWRITE_RENDERING_MODE_DEFAULT:
|
|
|
+- // As per DWRITE_RENDERING_MODE documentation, pick Natural for font
|
|
|
+- // sizes under 16 ppem
|
|
|
+- if (scaled_font->base.font_matrix.yy < 16.0f) {
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
|
|
|
+- } else {
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
|
|
|
+- }
|
|
|
+- break;
|
|
|
+- case DWRITE_RENDERING_MODE_OUTLINE:
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
|
|
|
+- break;
|
|
|
+- default:
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- DWRITE_MEASURING_MODE measureMode =
|
|
|
+- renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
|
|
|
+- renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
|
|
|
+- DWRITE_MEASURING_MODE_NATURAL;
|
|
|
+-
|
|
|
+- hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
|
|
|
+- 1.0f,
|
|
|
+- transform ? &dwmat : 0,
|
|
|
+- renderMode,
|
|
|
+- measureMode,
|
|
|
+- 0,
|
|
|
+- 0,
|
|
|
+- &analysis);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RECT bounds;
|
|
|
+- hr = analysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1,
|
|
|
+- &bounds);
|
|
|
+- if (FAILED(hr) ||
|
|
|
+- // with bitmap sizes of asian fonts, GetAlphaTextureBounds returns
|
|
|
+- // an empty rect, so we need to detect that and fall back
|
|
|
+- (bounds.top == 0 && bounds.bottom == 0 && num_glyphs > 0))
|
|
|
+- {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_rectangle_int_t cairo_bounds =
|
|
|
+- _cairo_rect_from_windows_rect(&bounds);
|
|
|
+-
|
|
|
+- cairo_region_t *region;
|
|
|
+- if (clip) {
|
|
|
+- region = cairo_region_copy(clip_region);
|
|
|
+-
|
|
|
+- cairo_region_intersect_rectangle(region, &cairo_bounds);
|
|
|
+- } else {
|
|
|
+- region = cairo_region_create_rectangle(&cairo_bounds);
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_region_auto_ptr region_ptr(region);
|
|
|
+-
|
|
|
+- if (cairo_region_is_empty(region)) {
|
|
|
+- // Nothing to do.
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- int bufferSize = cairo_bounds.width * cairo_bounds.height * 3;
|
|
|
+-
|
|
|
+- if (!bufferSize) {
|
|
|
+- // width == 0 || height == 0
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+- }
|
|
|
+-
|
|
|
+- // We add one byte so we can safely read an entire 32-bit int when copying
|
|
|
+- // the last 3 bytes of the alpha texture.
|
|
|
+- BYTE *texture = new BYTE[bufferSize + 1];
|
|
|
+- hr = analysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
|
|
|
+- &bounds, texture, bufferSize);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID3D10ShaderResourceView> srView;
|
|
|
+- ID3D10Device1 *device = dst->device->mD3D10Device;
|
|
|
+-
|
|
|
+- int textureWidth, textureHeight;
|
|
|
+-
|
|
|
+- if (cairo_bounds.width < TEXT_TEXTURE_WIDTH &&
|
|
|
+- cairo_bounds.height < TEXT_TEXTURE_HEIGHT)
|
|
|
+- {
|
|
|
+- // Use our cached TextTexture when it is big enough.
|
|
|
+- RefPtr<ID3D10Texture2D> tmpTexture;
|
|
|
+- CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
|
+- cairo_bounds.width, cairo_bounds.height,
|
|
|
+- 1, 1, 0);
|
|
|
+-
|
|
|
+- desc.Usage = D3D10_USAGE_STAGING;
|
|
|
+- desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
|
|
|
+-
|
|
|
+- hr = device->CreateTexture2D(&desc, NULL, &tmpTexture);
|
|
|
+-
|
|
|
+- D3D10_MAPPED_TEXTURE2D texMap;
|
|
|
+- hr = tmpTexture->Map(0, D3D10_MAP_WRITE, 0, &texMap);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- delete [] texture;
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- BYTE *alignedTextureData = (BYTE*)texMap.pData;
|
|
|
+- for (int y = 0; y < cairo_bounds.height; y++) {
|
|
|
+- for (int x = 0; x < cairo_bounds.width; x++) {
|
|
|
+- // Copy 3 Bpp source to 4 Bpp texture.
|
|
|
+- //
|
|
|
+- // Since we don't care what ends up in the alpha pixel of the
|
|
|
+- // destination, therefor we can simply copy a normal 32 bit
|
|
|
+- // integer each time, filling the alpha pixel of the destination
|
|
|
+- // with the first subpixel of the next pixel from the source.
|
|
|
+- *((int*)(alignedTextureData + (y * texMap.RowPitch) + x * 4)) =
|
|
|
+- *((int*)(texture + (y * cairo_bounds.width + x) * 3));
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- tmpTexture->Unmap(0);
|
|
|
+-
|
|
|
+- delete [] texture;
|
|
|
+-
|
|
|
+- D3D10_BOX box;
|
|
|
+- box.front = box.top = box.left = 0;
|
|
|
+- box.back = 1;
|
|
|
+- box.right = cairo_bounds.width;
|
|
|
+- box.bottom = cairo_bounds.height;
|
|
|
+-
|
|
|
+- device->CopySubresourceRegion(dst->device->mTextTexture, 0, 0, 0, 0, tmpTexture, 0, &box);
|
|
|
+-
|
|
|
+- srView = dst->device->mTextTextureView;
|
|
|
+-
|
|
|
+- textureWidth = TEXT_TEXTURE_WIDTH;
|
|
|
+- textureHeight = TEXT_TEXTURE_HEIGHT;
|
|
|
+- } else {
|
|
|
+- int alignedBufferSize = cairo_bounds.width * cairo_bounds.height * 4;
|
|
|
+-
|
|
|
+- // Create a one-off immutable texture from system memory.
|
|
|
+- BYTE *alignedTextureData = new BYTE[alignedBufferSize];
|
|
|
+- for (int y = 0; y < cairo_bounds.height; y++) {
|
|
|
+- for (int x = 0; x < cairo_bounds.width; x++) {
|
|
|
+- // Copy 3 Bpp source to 4 Bpp destination memory used for
|
|
|
+- // texture creation. D3D10 has no 3 Bpp texture format we can
|
|
|
+- // use.
|
|
|
+- //
|
|
|
+- // Since we don't care what ends up in the alpha pixel of the
|
|
|
+- // destination, therefor we can simply copy a normal 32 bit
|
|
|
+- // integer each time, filling the alpha pixel of the destination
|
|
|
+- // with the first subpixel of the next pixel from the source.
|
|
|
+- *((int*)(alignedTextureData + (y * cairo_bounds.width + x) * 4)) =
|
|
|
+- *((int*)(texture + (y * cairo_bounds.width + x) * 3));
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- D3D10_SUBRESOURCE_DATA data;
|
|
|
+-
|
|
|
+- CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
|
+- cairo_bounds.width, cairo_bounds.height,
|
|
|
+- 1, 1);
|
|
|
+- desc.Usage = D3D10_USAGE_IMMUTABLE;
|
|
|
+-
|
|
|
+- data.SysMemPitch = cairo_bounds.width * 4;
|
|
|
+- data.pSysMem = alignedTextureData;
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> tex;
|
|
|
+- hr = device->CreateTexture2D(&desc, &data, &tex);
|
|
|
+-
|
|
|
+- delete [] alignedTextureData;
|
|
|
+- delete [] texture;
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- hr = device->CreateShaderResourceView(tex, NULL, &srView);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- textureWidth = cairo_bounds.width;
|
|
|
+- textureHeight = cairo_bounds.height;
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Prepare destination surface for rendering.
|
|
|
+- RefPtr<ID3D10Texture2D> dstTexture;
|
|
|
+-
|
|
|
+- dst->surface->QueryInterface(&dstTexture);
|
|
|
+-
|
|
|
+- if (!dst->buffer_rt_view) {
|
|
|
+- hr = device->CreateRenderTargetView(dstTexture, NULL, &dst->buffer_rt_view);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- D3D10_TEXTURE2D_DESC tDesc;
|
|
|
+- dstTexture->GetDesc(&tDesc);
|
|
|
+- D3D10_VIEWPORT vp;
|
|
|
+- vp.Height = tDesc.Height;
|
|
|
+- vp.MinDepth = 0;
|
|
|
+- vp.MaxDepth = 1.0;
|
|
|
+- vp.TopLeftX = 0;
|
|
|
+- vp.TopLeftY = 0;
|
|
|
+- vp.Width = tDesc.Width;
|
|
|
+- device->RSSetViewports(1, &vp);
|
|
|
+-
|
|
|
+- ID3D10Effect *effect = dst->device->mSampleEffect;
|
|
|
+-
|
|
|
+- ID3D10RenderTargetView *rtViewPtr = dst->buffer_rt_view;
|
|
|
+-
|
|
|
+- device->OMSetRenderTargets(1, &rtViewPtr, 0);
|
|
|
+-
|
|
|
+- ID3D10EffectTechnique *technique = effect->GetTechniqueByName("SampleTextTexture");
|
|
|
+-
|
|
|
+- ID3D10EffectVectorVariable *quadDesc = effect->GetVariableByName("QuadDesc")->AsVector();
|
|
|
+- ID3D10EffectVectorVariable *texCoords = effect->GetVariableByName("TexCoords")->AsVector();
|
|
|
+- ID3D10EffectVectorVariable *textColor = effect->GetVariableByName("TextColor")->AsVector();
|
|
|
+-
|
|
|
+- float colorVal[] = { float(source->color.red * source->color.alpha),
|
|
|
+- float(source->color.green * source->color.alpha),
|
|
|
+- float(source->color.blue * source->color.alpha),
|
|
|
+- float(source->color.alpha) };
|
|
|
+- textColor->SetFloatVector(colorVal);
|
|
|
+-
|
|
|
+- float quadDescVal[4];
|
|
|
+- float texCoordsVal[4];
|
|
|
+-
|
|
|
+- // Draw a quad for each rectangle in the intersection of the clip and the
|
|
|
+- // text area.
|
|
|
+- for (int i = 0; i < cairo_region_num_rectangles(region); i++) {
|
|
|
+- cairo_rectangle_int_t quad;
|
|
|
+- cairo_region_get_rectangle(region, i, &quad);
|
|
|
+-
|
|
|
+- quadDescVal[0] = -1.0f + ((float)quad.x / (float)tDesc.Width) * 2.0f;
|
|
|
+- quadDescVal[1] = 1.0f - ((float)quad.y / (float)tDesc.Height) * 2.0f;
|
|
|
+- quadDescVal[2] = ((float)quad.width / (float)tDesc.Width) * 2.0f;
|
|
|
+- quadDescVal[3] = -((float)quad.height / (float)tDesc.Height) * 2.0f;
|
|
|
+-
|
|
|
+- texCoordsVal[0] = (float)(quad.x - cairo_bounds.x) / textureWidth;
|
|
|
+- texCoordsVal[1] = (float)(quad.y - cairo_bounds.y) / textureHeight;
|
|
|
+- texCoordsVal[2] = (float)quad.width / textureWidth;
|
|
|
+- texCoordsVal[3] = (float)quad.height / textureHeight;
|
|
|
+-
|
|
|
+- quadDesc->SetFloatVector(quadDescVal);
|
|
|
+- texCoords->SetFloatVector(texCoordsVal);
|
|
|
+-
|
|
|
+- _cairo_d2d_setup_for_blend(dst->device);
|
|
|
+- technique->GetPassByIndex(0)->Apply(0);
|
|
|
+-
|
|
|
+- ID3D10ShaderResourceView *srViewPtr = srView;
|
|
|
+- device->PSSetShaderResources(0, 1, &srViewPtr);
|
|
|
+-
|
|
|
+- device->Draw(4, 0);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_glyph_t *glyphs,
|
|
|
+- int num_glyphs,
|
|
|
+- cairo_scaled_font_t *scaled_font,
|
|
|
+- cairo_clip_t *clip)
|
|
|
+-{
|
|
|
+- cairo_int_status_t status;
|
|
|
+-
|
|
|
+- // TODO: Check font & surface for types.
|
|
|
+- cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
|
|
|
+- cairo_dwrite_font_face_t *dwriteff = reinterpret_cast<cairo_dwrite_font_face_t*>(scaled_font->font_face);
|
|
|
+- cairo_d2d_surface_t *dst = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- /* We can only handle dwrite fonts */
|
|
|
+- //XXX: this is checked by at least one caller
|
|
|
+- if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE)
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+-
|
|
|
+- op = _cairo_d2d_simplify_operator(op, source);
|
|
|
+-
|
|
|
+- /* We cannot handle operator SOURCE or CLEAR */
|
|
|
+- if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (op == CAIRO_OPERATOR_OVER && source->type == CAIRO_PATTERN_TYPE_SOLID &&
|
|
|
+- dst->base.content != CAIRO_CONTENT_COLOR &&
|
|
|
+- dst->base.permit_subpixel_antialiasing &&
|
|
|
+- dwritesf->antialias_mode == CAIRO_ANTIALIAS_SUBPIXEL)
|
|
|
+- {
|
|
|
+- // The D2D/DWrite drawing API's will not allow drawing subpixel AA to
|
|
|
+- // an RGBA surface. We do however want to do this if we know all text
|
|
|
+- // on a surface will be over opaque pixels, when this is the case
|
|
|
+- // we set the permit_subpixel_antialiasing flag on a surface. We then
|
|
|
+- // proceed to manually composite the glyphs to the surface.
|
|
|
+-
|
|
|
+- const cairo_solid_pattern_t *solid_src =
|
|
|
+- reinterpret_cast<const cairo_solid_pattern_t*>(source);
|
|
|
+- status = _cairo_dwrite_manual_show_glyphs_on_d2d_surface(surface,
|
|
|
+- op,
|
|
|
+- solid_src,
|
|
|
+- glyphs,
|
|
|
+- num_glyphs,
|
|
|
+- dwritesf,
|
|
|
+- clip);
|
|
|
+-
|
|
|
+- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1RenderTarget> target_rt = dst->rt;
|
|
|
+- cairo_rectangle_int_t fontArea;
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- if (op != CAIRO_OPERATOR_OVER) {
|
|
|
+-#endif
|
|
|
+- target_rt = _cairo_d2d_get_temp_rt(dst, clip);
|
|
|
+-
|
|
|
+- if (!target_rt) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-#ifndef ALWAYS_MANUAL_COMPOSITE
|
|
|
+- } else {
|
|
|
+- _begin_draw_state(dst);
|
|
|
+- status = (cairo_int_status_t)_cairo_d2d_set_clip (dst, clip);
|
|
|
+-
|
|
|
+- if (unlikely(status))
|
|
|
+- return status;
|
|
|
+- }
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- D2D1_TEXT_ANTIALIAS_MODE cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
|
|
|
+-
|
|
|
+- // If we're rendering to a temporary surface we cannot do sub-pixel AA.
|
|
|
+- if (dst->base.content != CAIRO_CONTENT_COLOR || dst->rt.get() != target_rt.get()) {
|
|
|
+- cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<IDWriteRenderingParams> params;
|
|
|
+- target_rt->GetTextRenderingParams(¶ms);
|
|
|
+-
|
|
|
+- DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
|
|
|
+- if (params) {
|
|
|
+- HRESULT hr = dwriteff->dwriteface->GetRecommendedRenderingMode(
|
|
|
+- (FLOAT)dwritesf->base.font_matrix.yy,
|
|
|
+- 1.0f,
|
|
|
+- DWRITE_MEASURING_MODE_NATURAL,
|
|
|
+- params,
|
|
|
+- &renderMode);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- // this probably never happens, but let's play it safe
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_DEFAULT;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept
|
|
|
+- switch (renderMode) {
|
|
|
+- case DWRITE_RENDERING_MODE_DEFAULT:
|
|
|
+- // As per DWRITE_RENDERING_MODE documentation, pick Natural for font
|
|
|
+- // sizes under 16 ppem
|
|
|
+- if (dwritesf->base.font_matrix.yy < 16.0f) {
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
|
|
|
+- } else {
|
|
|
+- renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
|
|
|
+- }
|
|
|
+- break;
|
|
|
+- case DWRITE_RENDERING_MODE_OUTLINE:
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- default:
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- switch (dwritesf->antialias_mode) {
|
|
|
+- case CAIRO_ANTIALIAS_NONE:
|
|
|
+- cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
|
+- break;
|
|
|
+- case CAIRO_ANTIALIAS_GRAY:
|
|
|
+- cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
|
|
|
+- break;
|
|
|
+- case CAIRO_ANTIALIAS_SUBPIXEL:
|
|
|
+- break;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (renderMode == DWRITE_RENDERING_MODE_ALIASED) {
|
|
|
+- cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- target_rt->SetTextAntialiasMode(cleartype_quality);
|
|
|
+-
|
|
|
+- DWRITE_MEASURING_MODE measureMode =
|
|
|
+- renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
|
|
|
+- renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
|
|
|
+- DWRITE_MEASURING_MODE_NATURAL;
|
|
|
+-
|
|
|
+- cairo_bool_t transform = FALSE;
|
|
|
+-
|
|
|
+- AutoDWriteGlyphRun run;
|
|
|
+- _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
|
|
|
+-
|
|
|
+- D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(&dwritesf->mat);
|
|
|
+-
|
|
|
+- if (transform) {
|
|
|
+- target_rt->SetTransform(mat);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (dst->rt.get() != target_rt.get()) {
|
|
|
+- RefPtr<IDWriteGlyphRunAnalysis> analysis;
|
|
|
+- DWRITE_MATRIX dwmat = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat);
|
|
|
+- DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
|
|
|
+- 1.0f,
|
|
|
+- transform ? &dwmat : 0,
|
|
|
+- renderMode,
|
|
|
+- measureMode,
|
|
|
+- 0,
|
|
|
+- 0,
|
|
|
+- &analysis);
|
|
|
+-
|
|
|
+- RECT bounds;
|
|
|
+- analysis->GetAlphaTextureBounds(scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE ?
|
|
|
+- DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1,
|
|
|
+- &bounds);
|
|
|
+- fontArea.x = bounds.left;
|
|
|
+- fontArea.y = bounds.top;
|
|
|
+- fontArea.width = bounds.right - bounds.left;
|
|
|
+- fontArea.height = bounds.bottom - bounds.top;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst, NULL,
|
|
|
+- source);
|
|
|
+-
|
|
|
+- if (!brush) {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (transform) {
|
|
|
+- D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse);
|
|
|
+- D2D1::Matrix3x2F mat_brush;
|
|
|
+-
|
|
|
+- // The brush matrix needs to be multiplied with the inverted matrix
|
|
|
+- // as well, to move the brush into the space of the glyphs. Before
|
|
|
+- // the render target transformation.
|
|
|
+- brush->GetTransform(&mat_brush);
|
|
|
+- mat_brush = mat_brush * mat_inverse;
|
|
|
+- brush->SetTransform(&mat_brush);
|
|
|
+- }
|
|
|
+-
|
|
|
+- target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, measureMode);
|
|
|
+-
|
|
|
+- if (transform) {
|
|
|
+- target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (target_rt.get() != dst->rt.get()) {
|
|
|
+- return _cairo_d2d_blend_temp_surface(dst, op, target_rt, clip, &fontArea);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return CAIRO_INT_STATUS_SUCCESS;
|
|
|
+-}
|
|
|
+-
|
|
|
+-static cairo_int_status_t
|
|
|
+-_cairo_d2d_show_glyphs (void *surface,
|
|
|
+- cairo_operator_t op,
|
|
|
+- const cairo_pattern_t *source,
|
|
|
+- cairo_glyph_t *glyphs,
|
|
|
+- int num_glyphs,
|
|
|
+- cairo_scaled_font_t *scaled_font,
|
|
|
+- cairo_clip_t *clip,
|
|
|
+- int *remaining_glyphs)
|
|
|
+-{
|
|
|
+- if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D ||
|
|
|
+- scaled_font->backend->type != CAIRO_FONT_TYPE_DWRITE)
|
|
|
+- {
|
|
|
+- return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- cairo_d2d_surface_t::TextRenderingState textRenderingState =
|
|
|
+- reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font)->rendering_mode;
|
|
|
+- if (d2dsurf->textRenderingState != textRenderingState) {
|
|
|
+- RefPtr<IDWriteRenderingParams> params =
|
|
|
+- DWriteFactory::RenderingParams(textRenderingState);
|
|
|
+- d2dsurf->rt->SetTextRenderingParams(params);
|
|
|
+- d2dsurf->textRenderingState = textRenderingState;
|
|
|
+- }
|
|
|
+- cairo_int_status_t status = (cairo_int_status_t)
|
|
|
+- _cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
|
|
|
+-
|
|
|
+- return status;
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-static cairo_bool_t
|
|
|
+-_cairo_d2d_getextents(void *surface,
|
|
|
+- cairo_rectangle_int_t *extents)
|
|
|
+-{
|
|
|
+- cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- extents->x = 0;
|
|
|
+- extents->y = 0;
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+- extents->width = size.width;
|
|
|
+- extents->height = size.height;
|
|
|
+- return TRUE;
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-/** Helper functions. */
|
|
|
+-
|
|
|
+-
|
|
|
+-
|
|
|
+-cairo_surface_t*
|
|
|
+-cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device,
|
|
|
+- HWND wnd,
|
|
|
+- cairo_content_t content)
|
|
|
+-{
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(cairo_device);
|
|
|
+- cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
|
|
+- new (newSurf) cairo_d2d_surface_t();
|
|
|
+-
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
|
|
|
+-
|
|
|
+- RECT rc;
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- newSurf->isDrawing = false;
|
|
|
+- ::GetClientRect(wnd, &rc);
|
|
|
+-
|
|
|
+- FLOAT dpiX;
|
|
|
+- FLOAT dpiY;
|
|
|
+- D2D1_SIZE_U sizePixels;
|
|
|
+- D2D1_SIZE_F size;
|
|
|
+-
|
|
|
+- dpiX = 96;
|
|
|
+- dpiY = 96;
|
|
|
+-
|
|
|
+-
|
|
|
+- sizePixels.width = rc.right - rc.left;
|
|
|
+- sizePixels.height = rc.bottom - rc.top;
|
|
|
+-
|
|
|
+- if (!sizePixels.width) {
|
|
|
+- sizePixels.width = 1;
|
|
|
+- }
|
|
|
+- if (!sizePixels.height) {
|
|
|
+- sizePixels.height = 1;
|
|
|
+- }
|
|
|
+- ID3D10Device1 *device = d2d_device->mD3D10Device;
|
|
|
+- RefPtr<IDXGIDevice> dxgiDevice;
|
|
|
+- RefPtr<IDXGIAdapter> dxgiAdapter;
|
|
|
+- RefPtr<IDXGIFactory> dxgiFactory;
|
|
|
+- D2D1_RENDER_TARGET_PROPERTIES props;
|
|
|
+- D2D1_BITMAP_PROPERTIES bitProps;
|
|
|
+-
|
|
|
+- device->QueryInterface(&dxgiDevice);
|
|
|
+- dxgiDevice->GetAdapter(&dxgiAdapter);
|
|
|
+- dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
|
|
|
+-
|
|
|
+- DXGI_SWAP_CHAIN_DESC swapDesc;
|
|
|
+- ::ZeroMemory(&swapDesc, sizeof(swapDesc));
|
|
|
+-
|
|
|
+- swapDesc.BufferDesc.Width = sizePixels.width;
|
|
|
+- swapDesc.BufferDesc.Height = sizePixels.height;
|
|
|
+- swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
+- swapDesc.BufferDesc.RefreshRate.Numerator = 60;
|
|
|
+- swapDesc.BufferDesc.RefreshRate.Denominator = 1;
|
|
|
+- swapDesc.SampleDesc.Count = 1;
|
|
|
+- swapDesc.SampleDesc.Quality = 0;
|
|
|
+- swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
|
+- swapDesc.BufferCount = 1;
|
|
|
+- swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
|
|
|
+- swapDesc.OutputWindow = wnd;
|
|
|
+- swapDesc.Windowed = TRUE;
|
|
|
+-
|
|
|
+- /**
|
|
|
+- * Create a swap chain, this swap chain will contain the backbuffer for
|
|
|
+- * the window we draw to. The front buffer is the full screen front
|
|
|
+- * buffer.
|
|
|
+- */
|
|
|
+- hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, &newSurf->dxgiChain);
|
|
|
+-
|
|
|
+- /**
|
|
|
+- * We do not want DXGI to intercept alt-enter events and make the window go
|
|
|
+- * fullscreen! This shouldn't be in the cairo backend but controlled through
|
|
|
+- * the device. See comments on mozilla bug 553603.
|
|
|
+- */
|
|
|
+- dxgiFactory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_HWND;
|
|
|
+- }
|
|
|
+- /** Get the backbuffer surface from the swap chain */
|
|
|
+- hr = newSurf->dxgiChain->GetBuffer(0,
|
|
|
+- IID_PPV_ARGS(&newSurf->surface));
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_HWND;
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->surface->QueryInterface(&newSurf->backBuf);
|
|
|
+-
|
|
|
+- size.width = sizePixels.width * dpiX;
|
|
|
+- size.height = sizePixels.height * dpiY;
|
|
|
+-
|
|
|
+- props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
|
|
|
+- dpiX,
|
|
|
+- dpiY,
|
|
|
+- D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE);
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(newSurf->backBuf,
|
|
|
+- props,
|
|
|
+- &newSurf->rt);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_HWND;
|
|
|
+- }
|
|
|
+-
|
|
|
+- bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- D2D1_ALPHA_MODE_PREMULTIPLIED));
|
|
|
+-
|
|
|
+- newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
|
|
+-
|
|
|
+- _d2d_clear_surface(newSurf);
|
|
|
+-
|
|
|
+- _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
|
|
|
+-
|
|
|
+- return reinterpret_cast<cairo_surface_t*>(newSurf);
|
|
|
+-
|
|
|
+-FAIL_HWND:
|
|
|
+- newSurf->~cairo_d2d_surface_t();
|
|
|
+- free(newSurf);
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-
|
|
|
+-cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create(cairo_device_t *device,
|
|
|
+- cairo_format_t format,
|
|
|
+- int width,
|
|
|
+- int height)
|
|
|
+-{
|
|
|
+- if (width == 0 || height == 0) {
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE));
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
|
|
+- new (newSurf) cairo_d2d_surface_t();
|
|
|
+-
|
|
|
+- DXGI_FORMAT dxgiformat = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
|
+- D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
|
+- if (format == CAIRO_FORMAT_ARGB32) {
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR_ALPHA);
|
|
|
+- } else if (format == CAIRO_FORMAT_RGB24) {
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR);
|
|
|
+- alpha = D2D1_ALPHA_MODE_IGNORE;
|
|
|
+- } else {
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA);
|
|
|
+- dxgiformat = DXGI_FORMAT_A8_UNORM;
|
|
|
+- }
|
|
|
+-
|
|
|
+-
|
|
|
+- newSurf->format = format;
|
|
|
+-
|
|
|
+- D2D1_SIZE_U sizePixels;
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- sizePixels.width = width;
|
|
|
+- sizePixels.height = height;
|
|
|
+-
|
|
|
+- CD3D10_TEXTURE2D_DESC desc(
|
|
|
+- dxgiformat,
|
|
|
+- sizePixels.width,
|
|
|
+- sizePixels.height
|
|
|
+- );
|
|
|
+- desc.MipLevels = 1;
|
|
|
+- desc.Usage = D3D10_USAGE_DEFAULT;
|
|
|
+- desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
|
|
+-
|
|
|
+- /* CreateTexture2D does not support D3D10_RESOURCE_MISC_GDI_COMPATIBLE with DXGI_FORMAT_A8_UNORM */
|
|
|
+- if (desc.Format != DXGI_FORMAT_A8_UNORM)
|
|
|
+- desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> texture;
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- D2D1_BITMAP_PROPERTIES bitProps;
|
|
|
+- D2D1_RENDER_TARGET_PROPERTIES props;
|
|
|
+-
|
|
|
+- hr = d2d_device->mD3D10Device->CreateTexture2D(&desc, NULL, &texture);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->surface = texture;
|
|
|
+-
|
|
|
+- /** Create the DXGI surface. */
|
|
|
+- hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha));
|
|
|
+-
|
|
|
+- if (desc.MiscFlags & D3D10_RESOURCE_MISC_GDI_COMPATIBLE)
|
|
|
+- props.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
|
|
|
+-
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
|
|
+- props,
|
|
|
+- &newSurf->rt);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- alpha));
|
|
|
+-
|
|
|
+- if (dxgiformat != DXGI_FORMAT_A8_UNORM) {
|
|
|
+- /* For some reason creation of shared bitmaps for A8 UNORM surfaces
|
|
|
+- * doesn't work even though the documentation suggests it does. The
|
|
|
+- * function will return an error if we try */
|
|
|
+- hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
|
|
|
+- dxgiSurface,
|
|
|
+- &bitProps,
|
|
|
+- &newSurf->surfaceBitmap);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
|
|
+-
|
|
|
+- _d2d_clear_surface(newSurf);
|
|
|
+-
|
|
|
+- _cairo_d2d_surface_init(newSurf, d2d_device, format);
|
|
|
+-
|
|
|
+- return reinterpret_cast<cairo_surface_t*>(newSurf);
|
|
|
+-
|
|
|
+-FAIL_CREATE:
|
|
|
+- newSurf->~cairo_d2d_surface_t();
|
|
|
+- free(newSurf);
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo_content_t content)
|
|
|
+-{
|
|
|
+- if (!device) {
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_DEVICE));
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
|
|
+- new (newSurf) cairo_d2d_surface_t();
|
|
|
+-
|
|
|
+- cairo_status_t status = CAIRO_STATUS_NO_MEMORY;
|
|
|
+- HRESULT hr;
|
|
|
+- RefPtr<ID3D10Texture2D> texture;
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- D2D1_BITMAP_PROPERTIES bitProps;
|
|
|
+- D2D1_RENDER_TARGET_PROPERTIES props;
|
|
|
+- DXGI_FORMAT format;
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+- D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
|
+-
|
|
|
+- hr = d2d_device->mD3D10Device->OpenSharedResource(handle,
|
|
|
+- __uuidof(ID3D10Resource),
|
|
|
+- (void**)&newSurf->surface);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- hr = newSurf->surface->QueryInterface(&dxgiSurface);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- dxgiSurface->GetDesc(&desc);
|
|
|
+- format = desc.Format;
|
|
|
+-
|
|
|
+- if (format == DXGI_FORMAT_B8G8R8A8_UNORM) {
|
|
|
+- if (content == CAIRO_CONTENT_ALPHA) {
|
|
|
+- status = CAIRO_STATUS_INVALID_CONTENT;
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
|
|
|
+- if (content == CAIRO_CONTENT_COLOR) {
|
|
|
+- alpha = D2D1_ALPHA_MODE_IGNORE;
|
|
|
+- }
|
|
|
+- } else if (format == DXGI_FORMAT_A8_UNORM) {
|
|
|
+- if (content != CAIRO_CONTENT_ALPHA) {
|
|
|
+- status = CAIRO_STATUS_INVALID_CONTENT;
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_ALPHA);
|
|
|
+- } else {
|
|
|
+- status = CAIRO_STATUS_INVALID_FORMAT;
|
|
|
+- // We don't know how to support this format!
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha));
|
|
|
+-
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
|
|
+- props,
|
|
|
+- &newSurf->rt);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- alpha));
|
|
|
+-
|
|
|
+- if (format != DXGI_FORMAT_A8_UNORM) {
|
|
|
+- /* For some reason creation of shared bitmaps for A8 UNORM surfaces
|
|
|
+- * doesn't work even though the documentation suggests it does. The
|
|
|
+- * function will return an error if we try */
|
|
|
+- hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
|
|
|
+- dxgiSurface,
|
|
|
+- &bitProps,
|
|
|
+- &newSurf->surfaceBitmap);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATEHANDLE;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
|
|
+-
|
|
|
+- _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
|
|
|
+-
|
|
|
+- return &newSurf->base;
|
|
|
+-
|
|
|
+-FAIL_CREATEHANDLE:
|
|
|
+- newSurf->~cairo_d2d_surface_t();
|
|
|
+- free(newSurf);
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(status));
|
|
|
+-}
|
|
|
+-
|
|
|
+-cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create_for_texture(cairo_device_t *device,
|
|
|
+- ID3D10Texture2D *texture,
|
|
|
+- cairo_content_t content)
|
|
|
+-{
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
|
|
|
+- new (newSurf) cairo_d2d_surface_t();
|
|
|
+-
|
|
|
+- D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
|
|
|
+- if (content == CAIRO_CONTENT_COLOR) {
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, CAIRO_CONTENT_COLOR);
|
|
|
+- alpha = D2D1_ALPHA_MODE_IGNORE;
|
|
|
+- } else {
|
|
|
+- _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, NULL, content);
|
|
|
+- }
|
|
|
+-
|
|
|
+- D2D1_SIZE_U sizePixels;
|
|
|
+- HRESULT hr;
|
|
|
+-
|
|
|
+- D3D10_TEXTURE2D_DESC desc;
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- D2D1_BITMAP_PROPERTIES bitProps;
|
|
|
+- D2D1_RENDER_TARGET_PROPERTIES props;
|
|
|
+-
|
|
|
+- texture->GetDesc(&desc);
|
|
|
+-
|
|
|
+- sizePixels.width = desc.Width;
|
|
|
+- sizePixels.height = desc.Height;
|
|
|
+-
|
|
|
+- newSurf->surface = texture;
|
|
|
+-
|
|
|
+- /** Create the DXGI surface. */
|
|
|
+- hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
|
|
|
+- D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha));
|
|
|
+-
|
|
|
+- if (desc.MiscFlags & D3D10_RESOURCE_MISC_GDI_COMPATIBLE)
|
|
|
+- props.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
|
|
|
+-
|
|
|
+- hr = sD2DFactory->CreateDxgiSurfaceRenderTarget(dxgiSurface,
|
|
|
+- props,
|
|
|
+- &newSurf->rt);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
|
|
|
+- alpha));
|
|
|
+-
|
|
|
+- if (content != CAIRO_CONTENT_ALPHA) {
|
|
|
+- /* For some reason creation of shared bitmaps for A8 UNORM surfaces
|
|
|
+- * doesn't work even though the documentation suggests it does. The
|
|
|
+- * function will return an error if we try */
|
|
|
+- hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
|
|
|
+- dxgiSurface,
|
|
|
+- &bitProps,
|
|
|
+- &newSurf->surfaceBitmap);
|
|
|
+-
|
|
|
+- if (FAILED(hr)) {
|
|
|
+- goto FAIL_CREATE;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
|
|
|
+-
|
|
|
+- _cairo_d2d_surface_init(newSurf, d2d_device, _cairo_format_from_content(content));
|
|
|
+-
|
|
|
+- return reinterpret_cast<cairo_surface_t*>(newSurf);
|
|
|
+-
|
|
|
+-FAIL_CREATE:
|
|
|
+- newSurf->~cairo_d2d_surface_t();
|
|
|
+- free(newSurf);
|
|
|
+- return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
|
|
|
+-}
|
|
|
+-
|
|
|
+-ID3D10Texture2D*
|
|
|
+-cairo_d2d_surface_get_texture(cairo_surface_t *surface)
|
|
|
+-{
|
|
|
+- if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- RefPtr<ID3D10Texture2D> texture;
|
|
|
+- d2dsurf->surface->QueryInterface(&texture);
|
|
|
+-
|
|
|
+- return texture;
|
|
|
+-}
|
|
|
+-
|
|
|
+-void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip)
|
|
|
+-{
|
|
|
+- if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return;
|
|
|
+- }
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- /** For now, we invalidate our storing texture with this operation. */
|
|
|
+- D2D1_POINT_2U point;
|
|
|
+- D3D10_BOX rect;
|
|
|
+- rect.front = 0;
|
|
|
+- rect.back = 1;
|
|
|
+-
|
|
|
+- RefPtr<IDXGISurface> dxgiSurface;
|
|
|
+- d2dsurf->surface->QueryInterface(&dxgiSurface);
|
|
|
+- DXGI_SURFACE_DESC desc;
|
|
|
+-
|
|
|
+- dxgiSurface->GetDesc(&desc);
|
|
|
+-
|
|
|
+- /**
|
|
|
+- * It's important we constrain the size of the clip region to the area of
|
|
|
+- * the surface. If we don't we might get a box that goes outside the
|
|
|
+- * surface, and CopySubresourceRegion will become very angry with us.
|
|
|
+- * It will cause a device failure and subsequent drawing will break.
|
|
|
+- */
|
|
|
+- clip->x = MAX(clip->x, 0);
|
|
|
+- clip->y = MAX(clip->y, 0);
|
|
|
+- clip->width = MIN(clip->width, desc.Width - clip->x);
|
|
|
+- clip->height = MIN(clip->height, desc.Height - clip->y);
|
|
|
+-
|
|
|
+- if (x < 0) {
|
|
|
+- point.x = (UINT32)clip->x;
|
|
|
+- rect.left = (UINT)(clip->x - x);
|
|
|
+- rect.right = (UINT)(clip->x + clip->width);
|
|
|
+- } else {
|
|
|
+- point.x = (UINT32)(clip->x + x);
|
|
|
+- rect.left = (UINT)clip->x;
|
|
|
+- rect.right = (UINT32)(clip->x + clip->width - x);
|
|
|
+- }
|
|
|
+- if (y < 0) {
|
|
|
+- point.y = (UINT32)clip->y;
|
|
|
+- rect.top = (UINT)(clip->y - y);
|
|
|
+- rect.bottom = (UINT)(clip->y + clip->height);
|
|
|
+- } else {
|
|
|
+- point.y = (UINT32)(clip->y + y);
|
|
|
+- rect.top = (UINT)clip->y;
|
|
|
+- rect.bottom = (UINT)(clip->y + clip->height - y);
|
|
|
+- }
|
|
|
+- ID3D10Texture2D *texture = _cairo_d2d_get_buffer_texture(d2dsurf);
|
|
|
+-
|
|
|
+- d2dsurf->device->mD3D10Device->CopyResource(texture, d2dsurf->surface);
|
|
|
+- d2dsurf->device->mD3D10Device->CopySubresourceRegion(d2dsurf->surface,
|
|
|
+- 0,
|
|
|
+- point.x,
|
|
|
+- point.y,
|
|
|
+- 0,
|
|
|
+- texture,
|
|
|
+- 0,
|
|
|
+- &rect);
|
|
|
+-
|
|
|
+-}
|
|
|
+-
|
|
|
+-HDC
|
|
|
+-cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents)
|
|
|
+-{
|
|
|
+- if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- /* We'll pop the clip here manually so that we'll stay in drawing state if we
|
|
|
+- * already are, we need to ensure d2dsurf->isDrawing manually then though
|
|
|
+- */
|
|
|
+-
|
|
|
+- /* Clips aren't allowed as per MSDN docs */
|
|
|
+- reset_clip(d2dsurf);
|
|
|
+-
|
|
|
+- if (!d2dsurf->isDrawing) {
|
|
|
+- /* GetDC must be called between BeginDraw/EndDraw */
|
|
|
+- d2dsurf->rt->BeginDraw();
|
|
|
+- d2dsurf->isDrawing = true;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RefPtr<ID2D1GdiInteropRenderTarget> interopRT;
|
|
|
+-
|
|
|
+- /* This QueryInterface call will always succeed even if the
|
|
|
+- * the render target doesn't support the ID2D1GdiInteropRenderTarget
|
|
|
+- * interface */
|
|
|
+- d2dsurf->rt->QueryInterface(&interopRT);
|
|
|
+-
|
|
|
+- HDC dc;
|
|
|
+- HRESULT rv;
|
|
|
+-
|
|
|
+- rv = interopRT->GetDC(retain_contents ? D2D1_DC_INITIALIZE_MODE_COPY :
|
|
|
+- D2D1_DC_INITIALIZE_MODE_CLEAR, &dc);
|
|
|
+-
|
|
|
+- if (FAILED(rv)) {
|
|
|
+- return NULL;
|
|
|
+- }
|
|
|
+-
|
|
|
+- return dc;
|
|
|
+-}
|
|
|
+-
|
|
|
+-void
|
|
|
+-cairo_d2d_release_dc(cairo_surface_t *surface, const cairo_rectangle_int_t *updated_rect)
|
|
|
+-{
|
|
|
+- if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
|
|
+- return;
|
|
|
+- }
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+-
|
|
|
+- RefPtr<ID2D1GdiInteropRenderTarget> interopRT;
|
|
|
+-
|
|
|
+- d2dsurf->rt->QueryInterface(&interopRT);
|
|
|
+-
|
|
|
+- if (!updated_rect) {
|
|
|
+- interopRT->ReleaseDC(NULL);
|
|
|
+- return;
|
|
|
+- }
|
|
|
+-
|
|
|
+- RECT r;
|
|
|
+- r.left = updated_rect->x;
|
|
|
+- r.top = updated_rect->y;
|
|
|
+- r.right = r.left + updated_rect->width;
|
|
|
+- r.bottom = r.top + updated_rect->height;
|
|
|
+-
|
|
|
+- interopRT->ReleaseDC(&r);
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_d2d_get_image_surface_cache_usage()
|
|
|
+-{
|
|
|
+- return _cairo_atomic_int_get(&cache_usage);
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_d2d_get_surface_vram_usage(cairo_device_t *device)
|
|
|
+-{
|
|
|
+- cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
|
|
+- return d2d_device->mVRAMUsage;
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_d2d_surface_get_width(cairo_surface_t *surface)
|
|
|
+-{
|
|
|
+- if (surface->backend != &cairo_d2d_surface_backend) {
|
|
|
+- _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
|
|
+- return 0;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+- return size.width;
|
|
|
+-}
|
|
|
+-
|
|
|
+-int
|
|
|
+-cairo_d2d_surface_get_height(cairo_surface_t *surface)
|
|
|
+-{
|
|
|
+- if (surface->backend != &cairo_d2d_surface_backend) {
|
|
|
+- _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
|
|
|
+- return 0;
|
|
|
+- }
|
|
|
+-
|
|
|
+- cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
|
|
+- D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
|
|
|
+- return size.height;
|
|
|
+-}
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
|
|
|
++++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
|
|
|
+@@ -34,18 +34,18 @@
|
|
|
+ * Bas Schouten <bschouten@mozilla.com>
|
|
|
+ */
|
|
|
+
|
|
|
+ #include "cairoint.h"
|
|
|
+
|
|
|
+ #include "cairo-win32-private.h"
|
|
|
+ #include "cairo-surface-private.h"
|
|
|
+ #include "cairo-clip-private.h"
|
|
|
+-
|
|
|
+-#include "cairo-d2d-private.h"
|
|
|
++#include "cairo-win32-refptr.h"
|
|
|
++
|
|
|
+ #include "cairo-dwrite-private.h"
|
|
|
+ #include "cairo-truetype-subset-private.h"
|
|
|
+ #include <float.h>
|
|
|
+
|
|
|
+ typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
|
|
|
+ D2D1_FACTORY_TYPE factoryType,
|
|
|
+ REFIID iid,
|
|
|
+ CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
|
|
|
+@@ -505,17 +505,17 @@ static cairo_status_t
|
|
|
+ dwriteFont->antialias_mode = default_quality;
|
|
|
+ } else {
|
|
|
+ dwriteFont->antialias_mode = options->antialias;
|
|
|
+ }
|
|
|
+
|
|
|
+ dwriteFont->manual_show_glyphs_allowed = TRUE;
|
|
|
+ dwriteFont->rendering_mode =
|
|
|
+ default_quality == CAIRO_ANTIALIAS_SUBPIXEL ?
|
|
|
+- cairo_d2d_surface_t::TEXT_RENDERING_NORMAL : cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE;
|
|
|
++ cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL : cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE;
|
|
|
+
|
|
|
+ return _cairo_scaled_font_set_metrics (*font, &extents);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Implementation cairo_dwrite_scaled_font_backend_t */
|
|
|
+ void
|
|
|
+ _cairo_dwrite_scaled_font_fini(void *scaled_font)
|
|
|
+ {
|
|
|
+@@ -1096,28 +1096,28 @@ cairo_dwrite_scaled_font_allow_manual_sh
|
|
|
+ cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
|
|
|
+ font->manual_show_glyphs_allowed = allowed;
|
|
|
+ }
|
|
|
+
|
|
|
+ void
|
|
|
+ cairo_dwrite_scaled_font_set_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font, cairo_bool_t force)
|
|
|
+ {
|
|
|
+ cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
|
|
|
+- if (force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_NORMAL) {
|
|
|
+- font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
|
|
|
+- } else if (!force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC) {
|
|
|
+- font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_NORMAL;
|
|
|
++ if (force && font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL) {
|
|
|
++ font->rendering_mode = cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC;
|
|
|
++ } else if (!force && font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC) {
|
|
|
++ font->rendering_mode = cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ cairo_bool_t
|
|
|
+ cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font)
|
|
|
+ {
|
|
|
+ cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
|
|
|
+- return font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
|
|
|
++ return font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC;
|
|
|
+ }
|
|
|
+
|
|
|
+ void
|
|
|
+ cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
|
|
|
+ int geometry, int mode)
|
|
|
+ {
|
|
|
+ DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
|
|
|
+ }
|
|
|
+@@ -1136,36 +1136,36 @@ cairo_int_status_t
|
|
|
+ cairo_dwrite_scaled_font_t *scaled_font,
|
|
|
+ const RECT &area)
|
|
|
+ {
|
|
|
+ IDWriteGdiInterop *gdiInterop;
|
|
|
+ DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
|
|
|
+ IDWriteBitmapRenderTarget *rt;
|
|
|
+ HRESULT rv;
|
|
|
+
|
|
|
+- cairo_d2d_surface_t::TextRenderingState renderingState =
|
|
|
++ cairo_dwrite_scaled_font_t::TextRenderingState renderingState =
|
|
|
+ scaled_font->rendering_mode;
|
|
|
+
|
|
|
+ rv = gdiInterop->CreateBitmapRenderTarget(surface->dc,
|
|
|
+ area.right - area.left,
|
|
|
+ area.bottom - area.top,
|
|
|
+ &rt);
|
|
|
+
|
|
|
+ if (FAILED(rv)) {
|
|
|
+ if (rv == E_OUTOFMEMORY) {
|
|
|
+ return (cairo_int_status_t)CAIRO_STATUS_NO_MEMORY;
|
|
|
+ } else {
|
|
|
+ return CAIRO_INT_STATUS_UNSUPPORTED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+- if ((renderingState == cairo_d2d_surface_t::TEXT_RENDERING_NORMAL ||
|
|
|
+- renderingState == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC) &&
|
|
|
++ if ((renderingState == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL ||
|
|
|
++ renderingState == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC) &&
|
|
|
+ !surface->base.permit_subpixel_antialiasing) {
|
|
|
+- renderingState = cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE;
|
|
|
++ renderingState = cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE;
|
|
|
+ IDWriteBitmapRenderTarget1* rt1;
|
|
|
+ rv = rt->QueryInterface(&rt1);
|
|
|
+
|
|
|
+ if (SUCCEEDED(rv) && rt1) {
|
|
|
+ rt1->SetTextAntialiasMode(DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
|
|
+ rt1->Release();
|
|
|
+ }
|
|
|
+ }
|
|
|
+@@ -1187,18 +1187,18 @@ cairo_int_status_t
|
|
|
+ BitBlt(rt->GetMemoryDC(),
|
|
|
+ 0, 0,
|
|
|
+ area.right - area.left, area.bottom - area.top,
|
|
|
+ surface->dc,
|
|
|
+ area.left, area.top,
|
|
|
+ SRCCOPY | NOMIRRORBITMAP);
|
|
|
+ DWRITE_MEASURING_MODE measureMode;
|
|
|
+ switch (renderingState) {
|
|
|
+- case cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC:
|
|
|
+- case cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE:
|
|
|
++ case cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC:
|
|
|
++ case cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE:
|
|
|
+ measureMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ measureMode = DWRITE_MEASURING_MODE_NATURAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ HRESULT hr = rt->DrawGlyphRun(0, 0, measureMode, run, params, color);
|
|
|
+ BitBlt(surface->dc,
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-dwrite-private.h b/gfx/cairo/cairo/src/cairo-dwrite-private.h
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-dwrite-private.h
|
|
|
++++ b/gfx/cairo/cairo/src/cairo-dwrite-private.h
|
|
|
+@@ -46,17 +46,23 @@ typedef HRESULT (WINAPI*DWriteCreateFact
|
|
|
+ /* cairo_scaled_font_t implementation */
|
|
|
+ struct _cairo_dwrite_scaled_font {
|
|
|
+ cairo_scaled_font_t base;
|
|
|
+ cairo_matrix_t mat;
|
|
|
+ cairo_matrix_t mat_inverse;
|
|
|
+ cairo_antialias_t antialias_mode;
|
|
|
+ DWRITE_MEASURING_MODE measuring_mode;
|
|
|
+ cairo_bool_t manual_show_glyphs_allowed;
|
|
|
+- cairo_d2d_surface_t::TextRenderingState rendering_mode;
|
|
|
++ enum TextRenderingState {
|
|
|
++ TEXT_RENDERING_UNINITIALIZED,
|
|
|
++ TEXT_RENDERING_NO_CLEARTYPE,
|
|
|
++ TEXT_RENDERING_NORMAL,
|
|
|
++ TEXT_RENDERING_GDI_CLASSIC
|
|
|
++ };
|
|
|
++ TextRenderingState rendering_mode;
|
|
|
+ };
|
|
|
+ typedef struct _cairo_dwrite_scaled_font cairo_dwrite_scaled_font_t;
|
|
|
+
|
|
|
+ class DWriteFactory
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ static IDWriteFactory *Instance()
|
|
|
+ {
|
|
|
+@@ -97,28 +103,28 @@ public:
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ IDWriteFontFamily *family;
|
|
|
+ SystemCollection()->GetFontFamily(idx, &family);
|
|
|
+ return family;
|
|
|
+ }
|
|
|
+
|
|
|
+- static IDWriteRenderingParams *RenderingParams(cairo_d2d_surface_t::TextRenderingState mode)
|
|
|
++ static IDWriteRenderingParams *RenderingParams(cairo_dwrite_scaled_font_t::TextRenderingState mode)
|
|
|
+ {
|
|
|
+ if (!mDefaultRenderingParams ||
|
|
|
+ !mForceGDIClassicRenderingParams ||
|
|
|
+ !mCustomClearTypeRenderingParams)
|
|
|
+ {
|
|
|
+ CreateRenderingParams();
|
|
|
+ }
|
|
|
+ IDWriteRenderingParams *params;
|
|
|
+- if (mode == cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE) {
|
|
|
++ if (mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE) {
|
|
|
+ params = mDefaultRenderingParams;
|
|
|
+- } else if (mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC && mRenderingMode < 0) {
|
|
|
++ } else if (mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC && mRenderingMode < 0) {
|
|
|
+ params = mForceGDIClassicRenderingParams;
|
|
|
+ } else {
|
|
|
+ params = mCustomClearTypeRenderingParams;
|
|
|
+ }
|
|
|
+ if (params) {
|
|
|
+ params->AddRef();
|
|
|
+ }
|
|
|
+ return params;
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-features.h.in b/gfx/cairo/cairo/src/cairo-features.h.in
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-features.h.in
|
|
|
++++ b/gfx/cairo/cairo/src/cairo-features.h.in
|
|
|
+@@ -78,18 +78,16 @@
|
|
|
+ @QT_SURFACE_FEATURE@
|
|
|
+
|
|
|
+ @FT_FONT_FEATURE@
|
|
|
+
|
|
|
+ @WIN32_FONT_FEATURE@
|
|
|
+
|
|
|
+ @WIN32_DWRITE_FONT_FEATURE@
|
|
|
+
|
|
|
+-@WIN32_D2D_SURFACE_FEATURE@
|
|
|
+-
|
|
|
+ @QUARTZ_FONT_FEATURE@
|
|
|
+
|
|
|
+ @TEE_SURFACE_FEATURE@
|
|
|
+
|
|
|
+ @PNG_FUNCTIONS_FEATURE@
|
|
|
+
|
|
|
+ @FC_FONT_FEATURE@
|
|
|
+ #endif
|
|
|
+diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h
|
|
|
+--- a/gfx/cairo/cairo/src/cairo-win32.h
|
|
|
++++ b/gfx/cairo/cairo/src/cairo-win32.h
|
|
|
+@@ -146,194 +146,15 @@ int
|
|
|
+ cairo_dwrite_get_cleartype_rendering_mode();
|
|
|
+
|
|
|
+ #endif /* CAIRO_HAS_DWRITE_FONT */
|
|
|
+
|
|
|
+ struct IDirect3DSurface9;
|
|
|
+ cairo_public cairo_surface_t *
|
|
|
+ cairo_win32_surface_create_with_d3dsurface9 (struct IDirect3DSurface9 *surface);
|
|
|
+
|
|
|
+-
|
|
|
+-#if CAIRO_HAS_D2D_SURFACE
|
|
|
+-
|
|
|
+-struct _cairo_device
|
|
|
+-{
|
|
|
+- int type;
|
|
|
+- int refcount;
|
|
|
+-};
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D2D device
|
|
|
+- *
|
|
|
+- * \return New D2D device, NULL if creation failed.
|
|
|
+- */
|
|
|
+-cairo_device_t *
|
|
|
+-cairo_d2d_create_device();
|
|
|
+-
|
|
|
+-cairo_device_t *
|
|
|
+-cairo_d2d_create_device_from_d3d10device(struct ID3D10Device1 *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Releases a D2D device.
|
|
|
+- *
|
|
|
+- * \return References left to the device
|
|
|
+- */
|
|
|
+-int
|
|
|
+-cairo_release_device(cairo_device_t *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Addrefs a D2D device.
|
|
|
+- *
|
|
|
+- * \return References to the device
|
|
|
+- */
|
|
|
+-int
|
|
|
+-cairo_addref_device(cairo_device_t *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Flushes a D3D device. In most cases the surface backend will do this
|
|
|
+- * internally, but when using a surfaces created from a shared handle this
|
|
|
+- * should be executed manually when a different device is going to be accessing
|
|
|
+- * the same surface data. This will also block until the device is finished
|
|
|
+- * processing all work.
|
|
|
+- */
|
|
|
+-void
|
|
|
+-cairo_d2d_finish_device(cairo_device_t *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Gets the D3D10 device used by a certain cairo_device_t.
|
|
|
+- */
|
|
|
+-struct ID3D10Device1*
|
|
|
+-cairo_d2d_device_get_device(cairo_device_t *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D2D surface for an HWND
|
|
|
+- *
|
|
|
+- * \param device Device used to create the surface
|
|
|
+- * \param wnd Handle for the window
|
|
|
+- * \param content Content of the window, should be COLOR_ALPHA for transparent windows
|
|
|
+- * \return New cairo surface
|
|
|
+- */
|
|
|
+-cairo_public cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create_for_hwnd(cairo_device_t *device, HWND wnd, cairo_content_t content);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D2D surface of a certain size.
|
|
|
+- *
|
|
|
+- * \param device Device used to create the surface
|
|
|
+- * \param format Cairo format of the surface
|
|
|
+- * \param width Width of the surface
|
|
|
+- * \param height Height of the surface
|
|
|
+- * \return New cairo surface
|
|
|
+- */
|
|
|
+-cairo_public cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create(cairo_device_t *device,
|
|
|
+- cairo_format_t format,
|
|
|
+- int width,
|
|
|
+- int height);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D3D surface from a Texture SharedHandle, this is obtained from a
|
|
|
+- * CreateTexture call on a D3D9 device. This has to be an A8R8G8B8 format
|
|
|
+- * or an A8 format, the treatment of the alpha channel can be indicated using
|
|
|
+- * the content parameter.
|
|
|
+- *
|
|
|
+- * \param device Device used to create the surface
|
|
|
+- * \param handle Shared handle to the texture we want to wrap
|
|
|
+- * \param content Content of the texture, COLOR_ALPHA for ARGB
|
|
|
+- * \return New cairo surface
|
|
|
+- */
|
|
|
+-cairo_public cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create_for_handle(cairo_device_t *device, HANDLE handle, cairo_content_t content);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Create a D3D surface from an ID3D10Texture2D texture, this is obtained from a
|
|
|
+- * CreateTexture2D call on a D3D10 device. This has to be an A8R8G8B8 format
|
|
|
+- * or an A8 format, the treatment of the alpha channel can be indicated using
|
|
|
+- * the content parameter.
|
|
|
+- *
|
|
|
+- * \param device Device used to create the surface
|
|
|
+- * \param texture Texture that we want to wrap
|
|
|
+- * \param content Content of the texture
|
|
|
+- * \return New cairo surface
|
|
|
+- */
|
|
|
+-cairo_public cairo_surface_t *
|
|
|
+-cairo_d2d_surface_create_for_texture(cairo_device_t *device,
|
|
|
+- struct ID3D10Texture2D *texture,
|
|
|
+- cairo_content_t content);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get the ID3D10Texture2D used for a surface.
|
|
|
+- */
|
|
|
+-cairo_public struct ID3D10Texture2D *cairo_d2d_surface_get_texture(cairo_surface_t *surf);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Present the backbuffer for a surface create for an HWND. This needs
|
|
|
+- * to be called when the owner of the original window surface wants to
|
|
|
+- * actually present the executed drawing operations to the screen.
|
|
|
+- *
|
|
|
+- * \param surface D2D surface.
|
|
|
+- */
|
|
|
+-void cairo_d2d_present_backbuffer(cairo_surface_t *surface);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Scroll the surface, this only moves the surface graphics, it does not
|
|
|
+- * actually scroll child windows or anything like that. Nor does it invalidate
|
|
|
+- * that area of the window.
|
|
|
+- *
|
|
|
+- * \param surface The d2d surface this operation should apply to.
|
|
|
+- * \param x The x delta for the movement
|
|
|
+- * \param y The y delta for the movement
|
|
|
+- * \param clip The clip rectangle, the is the 'part' of the surface that needs
|
|
|
+- * scrolling.
|
|
|
+- */
|
|
|
+-void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get a DC for the current render target. When selecting the retention option this
|
|
|
+- * call can be relatively slow, since it may require reading back contents from the
|
|
|
+- * hardware surface.
|
|
|
+- *
|
|
|
+- * \note This must be matched by a call to ReleaseDC!
|
|
|
+- *
|
|
|
+- * \param retain_contents If true the current contents of the RT is copied to the DC,
|
|
|
+- * otherwise the DC is initialized to transparent black.
|
|
|
+- */
|
|
|
+-HDC cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Release the DC acquired through GetDC(). Optionally an update region may be specified
|
|
|
+- *
|
|
|
+- * \param updated_rect The area of the DC that was updated, if null the entire dc will
|
|
|
+- * be updated.
|
|
|
+- */
|
|
|
+-void cairo_d2d_release_dc(cairo_surface_t *surcace, const cairo_rectangle_int_t *updated_rect);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get an estimate of the amount of (video) RAM which is currently in use by the D2D
|
|
|
+- * internal image surface cache.
|
|
|
+- */
|
|
|
+-int cairo_d2d_get_image_surface_cache_usage();
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get an estimate of the amount of VRAM which is currently used by the d2d
|
|
|
+- * surfaces for a device. This does -not- include the internal image surface
|
|
|
+- * cache.
|
|
|
+- */
|
|
|
+-int cairo_d2d_get_surface_vram_usage(cairo_device_t *device);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get the width of the surface.
|
|
|
+- */
|
|
|
+-int cairo_d2d_surface_get_width(cairo_surface_t *surface);
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Get the height of the surface.
|
|
|
+- */
|
|
|
+-int cairo_d2d_surface_get_height(cairo_surface_t *surface);
|
|
|
+-#endif
|
|
|
+-
|
|
|
+ CAIRO_END_DECLS
|
|
|
+
|
|
|
+ #else /* CAIRO_HAS_WIN32_SURFACE */
|
|
|
+ # error Cairo was not compiled with support for the win32 backend
|
|
|
+ #endif /* CAIRO_HAS_WIN32_SURFACE */
|
|
|
+
|
|
|
+ #endif /* _CAIRO_WIN32_H_ */
|
|
|
+diff --git a/gfx/cairo/cairo/src/moz.build b/gfx/cairo/cairo/src/moz.build
|
|
|
+--- a/gfx/cairo/cairo/src/moz.build
|
|
|
++++ b/gfx/cairo/cairo/src/moz.build
|
|
|
+@@ -35,20 +35,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] not in (
|
|
|
+
|
|
|
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|
|
+ EXPORTS.cairo += [
|
|
|
+ 'cairo-win32.h',
|
|
|
+ ]
|
|
|
+ SOURCES += [
|
|
|
+ 'cairo-dwrite-font.cpp',
|
|
|
+ ]
|
|
|
+- if CONFIG['MOZ_ENABLE_D2D_SURFACE']:
|
|
|
+- SOURCES += [
|
|
|
+- 'cairo-d2d-surface.cpp',
|
|
|
+- ]
|
|
|
+ SOURCES += [
|
|
|
+ 'cairo-win32-font.c',
|
|
|
+ 'cairo-win32-surface.c',
|
|
|
+ ]
|
|
|
+ DEFINES['DISABLE_SOME_FLOATING_POINT'] = True
|
|
|
+ DEFINES['CAIRO_WIN32_STATIC_BUILD'] = True
|
|
|
+ if CONFIG['NS_PRINTING']:
|
|
|
+ SOURCES += [
|
|
|
+diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h
|
|
|
+--- a/gfx/thebes/gfxWindowsPlatform.h
|
|
|
++++ b/gfx/thebes/gfxWindowsPlatform.h
|
|
|
+@@ -3,17 +3,17 @@
|
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
+
|
|
|
+ #ifndef GFX_WINDOWS_PLATFORM_H
|
|
|
+ #define GFX_WINDOWS_PLATFORM_H
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+- * XXX to get CAIRO_HAS_D2D_SURFACE, CAIRO_HAS_DWRITE_FONT
|
|
|
++ * XXX to get CAIRO_HAS_DWRITE_FONT
|
|
|
+ * and cairo_win32_scaled_font_select_font
|
|
|
+ */
|
|
|
+ #include "cairo-win32.h"
|
|
|
+
|
|
|
+ #include "gfxCrashReporterUtils.h"
|
|
|
+ #include "gfxFontUtils.h"
|
|
|
+ #include "gfxWindowsSurface.h"
|
|
|
+ #include "gfxFont.h"
|
|
|
+diff --git a/old-configure.in b/old-configure.in
|
|
|
+--- a/old-configure.in
|
|
|
++++ b/old-configure.in
|
|
|
+@@ -2576,52 +2576,44 @@ fi
|
|
|
+
|
|
|
+ case "$MOZ_WIDGET_TOOLKIT" in
|
|
|
+ cocoa)
|
|
|
+ QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1"
|
|
|
+ QUARTZ_IMAGE_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE 1"
|
|
|
+ QUARTZ_FONT_FEATURE="#define CAIRO_HAS_QUARTZ_FONT 1"
|
|
|
+ ;;
|
|
|
+ windows)
|
|
|
+- WIN32_D2D_SURFACE_FEATURE="#define CAIRO_HAS_D2D_SURFACE 1"
|
|
|
+ WIN32_DWRITE_FONT_FEATURE="#define CAIRO_HAS_DWRITE_FONT 1"
|
|
|
+ WIN32_FONT_FEATURE="#define CAIRO_HAS_WIN32_FONT 1"
|
|
|
+ WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1"
|
|
|
+- MOZ_ENABLE_D2D_SURFACE=1
|
|
|
+
|
|
|
+ if test "$COMPILE_ENVIRONMENT"; then
|
|
|
+-
|
|
|
+- dnl D3D10 Layers depend on D2D Surfaces.
|
|
|
+- if test -n "$WIN32_D2D_SURFACE_FEATURE"; then
|
|
|
+- MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
|
|
|
+- fi
|
|
|
++ MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
|
|
|
+ fi
|
|
|
+ ;;
|
|
|
+ esac
|
|
|
+ if test "$USE_FC_FREETYPE"; then
|
|
|
+ FC_FONT_FEATURE="#define CAIRO_HAS_FC_FONT 1"
|
|
|
+ fi
|
|
|
+ AC_SUBST(MOZ_ENABLE_CAIRO_FT)
|
|
|
+-AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
|
|
|
+ AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
|
|
|
+
|
|
|
+ AC_SUBST(PS_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(SVG_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(XLIB_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(XLIB_XRENDER_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(QUARTZ_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(QUARTZ_IMAGE_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(WIN32_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(OS2_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(DIRECTFB_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(FT_FONT_FEATURE)
|
|
|
+ AC_SUBST(FC_FONT_FEATURE)
|
|
|
+ AC_SUBST(WIN32_FONT_FEATURE)
|
|
|
+ AC_SUBST(WIN32_DWRITE_FONT_FEATURE)
|
|
|
+-AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(QUARTZ_FONT_FEATURE)
|
|
|
+ AC_SUBST(PNG_FUNCTIONS_FEATURE)
|
|
|
+ AC_SUBST(QT_SURFACE_FEATURE)
|
|
|
+ AC_SUBST(TEE_SURFACE_FEATURE)
|
|
|
+
|
|
|
+ if test "$MOZ_X11"; then
|
|
|
+ MOZ_CAIRO_OSLIBS="$MOZ_CAIRO_OSLIBS $XLDFLAGS -lXrender"
|
|
|
+ fi
|