<commit_before>// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NAZARA_OPENGLRENDERER_CONTEXTIMPL_HPP
#define NAZARA_OPENGLRENDERER_CONTEXTIMPL_HPP

#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/DynLib.hpp>
#include <Nazara/OpenGLRenderer/Config.hpp>
#include <Nazara/OpenGLRenderer/OpenGLVaoCache.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Loader.hpp>
#include <Nazara/Renderer/RenderStates.hpp>
#include <array>
#include <string>
#include <unordered_set>

namespace Nz
{
	class OpenGLDevice;
}

namespace Nz::GL
{
	enum class BufferTarget
	{
		Array,
		CopyRead,
		CopyWrite,
		ElementArray,
		PixelPack,
		PixelUnpack,
		TransformFeedback,
		Uniform,

		Max = Uniform
	};

	enum class ContextType
	{
		OpenGL,
		OpenGL_ES
	};

	enum class Extension
	{
		SpirV,
		TextureFilterAnisotropic,
		TextureCompressionS3tc,

		Max = TextureFilterAnisotropic
	};

	enum class ExtensionStatus
	{
		NotSupported,

		ARB,
		EXT,
		KHR
	};

	enum class FramebufferTarget
	{
		Draw,
		Read
	};

	enum class TextureTarget
	{
		Cubemap,
		CubemapNegativeX,
		CubemapNegativeY,
		CubemapNegativeZ,
		CubemapPositiveX,
		CubemapPositiveY,
		CubemapPositiveZ,
		Target2D,
		Target2D_Array,
		Target3D,

		Max = Target3D
	};

	struct ContextParams
	{
		ContextType type = ContextType::OpenGL_ES;
		bool doubleBuffering = true;
		unsigned int bitsPerPixel = 32;
		unsigned int depthBits = 24;
		unsigned int glMajorVersion = 0;
		unsigned int glMinorVersion = 0;
		unsigned int sampleCount = 1;
		unsigned int stencilBits = 8;
	};

	class NAZARA_OPENGLRENDERER_API Context
	{
		struct SymbolLoader;
		friend SymbolLoader;

		public:
			inline Context(const OpenGLDevice* device);
			virtual ~Context();

			void BindBuffer(BufferTarget target, GLuint buffer, bool force = false) const;
			void BindFramebuffer(GLuint fbo) const;
			void BindFramebuffer(FramebufferTarget target, GLuint fbo) const;
			void BindProgram(GLuint program) const;
			void BindSampler(UInt32 textureUnit, GLuint sampler) const;
			void BindTexture(TextureTarget target, GLuint texture) const;
			void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const;
			void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
			void BindVertexArray(GLuint vertexArray, bool force = false) const;

			bool ClearErrorStack() const;

			virtual void EnableVerticalSync(bool enabled) = 0;

			inline const OpenGLDevice* GetDevice() const;
			inline ExtensionStatus GetExtensionStatus(Extension extension) const;
			inline GLFunction GetFunctionByIndex(std::size_t funcIndex) const;
			inline const OpenGLVaoCache& GetVaoCache() const;
			inline const ContextParams& GetParams() const;

			inline bool IsExtensionSupported(Extension extension) const;
			inline bool IsExtensionSupported(const std::string& extension) const;

			bool Initialize(const ContextParams& params);

			inline void NotifyBufferDestruction(GLuint buffer) const;
			inline void NotifyFramebufferDestruction(GLuint fbo) const;
			inline void NotifyProgramDestruction(GLuint program) const;
			inline void NotifySamplerDestruction(GLuint sampler) const;
			inline void NotifyTextureDestruction(GLuint texture) const;
			inline void NotifyVertexArrayDestruction(GLuint vao) const;

			bool ProcessErrorStack() const;

			inline void ResetColorWriteMasks() const;
			inline void ResetDepthWriteMasks() const;
			inline void ResetStencilWriteMasks() const;

			void SetCurrentTextureUnit(UInt32 textureUnit) const;
			void SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const;
			void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const;

			virtual void SwapBuffers() = 0;

			void UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const;

#define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr;
			NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC

			static const Context* GetCurrentContext();
			static bool SetCurrentContext(const Context* context);

		protected:
			virtual bool Activate() const = 0;
			virtual void Desactivate() const = 0;
			virtual const Loader& GetLoader() = 0;
			void OnContextRelease();

			virtual bool ImplementFallback(const std::string_view& function);

			static void NotifyContextDestruction(Context* context);

			ContextParams m_params;

		private:
			void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const;

			enum class FunctionIndex
			{
#define NAZARA_OPENGLRENDERER_FUNC(name, sig) name,
				NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC

				Count
			};

			struct State
			{
				struct Box
				{
					GLint x, y;
					GLsizei width, height;
				};

				struct TextureUnit
				{
					GLuint sampler = 0;
					std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> textureTargets = { 0 };
				};

				struct UniformBufferUnit
				{
					GLuint buffer = 0;
					GLintptr offset = 0;
					GLsizeiptr size = 0;
				};

				std::array<GLuint, UnderlyingCast(BufferTarget::Max) + 1> bufferTargets = { 0 };
				std::vector<TextureUnit> textureUnits;
				std::vector<UniformBufferUnit> uboUnits;
				Box scissorBox;
				Box viewport;
				GLuint boundProgram = 0;
				GLuint boundDrawFBO = 0;
				GLuint boundReadFBO = 0;
				GLuint boundVertexArray = 0;
				UInt32 currentTextureUnit = 0;
				RenderStates renderStates;
			};

			std::array<ExtensionStatus, UnderlyingCast(Extension::Max) + 1> m_extensionStatus;
			std::array<GLFunction, UnderlyingCast(FunctionIndex::Count)> m_originalFunctionPointer;
			std::unordered_set<std::string> m_supportedExtensions;
			OpenGLVaoCache m_vaoCache;
			const OpenGLDevice* m_device;
			mutable State m_state;
	};
}

#include <Nazara/OpenGLRenderer/Wrapper/Context.inl>

#endif
<commit_msg>Update Context.hpp<commit_after>// Copyright (C) 2020 Jérôme Leclercq
// This file is part of the "Nazara Engine - OpenGL Renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp

#pragma once

#ifndef NAZARA_OPENGLRENDERER_CONTEXTIMPL_HPP
#define NAZARA_OPENGLRENDERER_CONTEXTIMPL_HPP

#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/DynLib.hpp>
#include <Nazara/OpenGLRenderer/Config.hpp>
#include <Nazara/OpenGLRenderer/OpenGLVaoCache.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/CoreFunctions.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Loader.hpp>
#include <Nazara/Renderer/RenderStates.hpp>
#include <array>
#include <string>
#include <unordered_set>

namespace Nz
{
	class OpenGLDevice;
}

namespace Nz::GL
{
	enum class BufferTarget
	{
		Array,
		CopyRead,
		CopyWrite,
		ElementArray,
		PixelPack,
		PixelUnpack,
		TransformFeedback,
		Uniform,

		Max = Uniform
	};

	enum class ContextType
	{
		OpenGL,
		OpenGL_ES
	};

	enum class Extension
	{
		SpirV,
		TextureCompressionS3tc,
		TextureFilterAnisotropic,

		Max = TextureFilterAnisotropic
	};

	enum class ExtensionStatus
	{
		NotSupported,

		ARB,
		EXT,
		KHR
	};

	enum class FramebufferTarget
	{
		Draw,
		Read
	};

	enum class TextureTarget
	{
		Cubemap,
		CubemapNegativeX,
		CubemapNegativeY,
		CubemapNegativeZ,
		CubemapPositiveX,
		CubemapPositiveY,
		CubemapPositiveZ,
		Target2D,
		Target2D_Array,
		Target3D,

		Max = Target3D
	};

	struct ContextParams
	{
		ContextType type = ContextType::OpenGL_ES;
		bool doubleBuffering = true;
		unsigned int bitsPerPixel = 32;
		unsigned int depthBits = 24;
		unsigned int glMajorVersion = 0;
		unsigned int glMinorVersion = 0;
		unsigned int sampleCount = 1;
		unsigned int stencilBits = 8;
	};

	class NAZARA_OPENGLRENDERER_API Context
	{
		struct SymbolLoader;
		friend SymbolLoader;

		public:
			inline Context(const OpenGLDevice* device);
			virtual ~Context();

			void BindBuffer(BufferTarget target, GLuint buffer, bool force = false) const;
			void BindFramebuffer(GLuint fbo) const;
			void BindFramebuffer(FramebufferTarget target, GLuint fbo) const;
			void BindProgram(GLuint program) const;
			void BindSampler(UInt32 textureUnit, GLuint sampler) const;
			void BindTexture(TextureTarget target, GLuint texture) const;
			void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const;
			void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
			void BindVertexArray(GLuint vertexArray, bool force = false) const;

			bool ClearErrorStack() const;

			virtual void EnableVerticalSync(bool enabled) = 0;

			inline const OpenGLDevice* GetDevice() const;
			inline ExtensionStatus GetExtensionStatus(Extension extension) const;
			inline GLFunction GetFunctionByIndex(std::size_t funcIndex) const;
			inline const OpenGLVaoCache& GetVaoCache() const;
			inline const ContextParams& GetParams() const;

			inline bool IsExtensionSupported(Extension extension) const;
			inline bool IsExtensionSupported(const std::string& extension) const;

			bool Initialize(const ContextParams& params);

			inline void NotifyBufferDestruction(GLuint buffer) const;
			inline void NotifyFramebufferDestruction(GLuint fbo) const;
			inline void NotifyProgramDestruction(GLuint program) const;
			inline void NotifySamplerDestruction(GLuint sampler) const;
			inline void NotifyTextureDestruction(GLuint texture) const;
			inline void NotifyVertexArrayDestruction(GLuint vao) const;

			bool ProcessErrorStack() const;

			inline void ResetColorWriteMasks() const;
			inline void ResetDepthWriteMasks() const;
			inline void ResetStencilWriteMasks() const;

			void SetCurrentTextureUnit(UInt32 textureUnit) const;
			void SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const;
			void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const;

			virtual void SwapBuffers() = 0;

			void UpdateStates(const RenderStates& renderStates, bool isViewportFlipped) const;

#define NAZARA_OPENGLRENDERER_FUNC(name, sig) sig name = nullptr;
			NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC

			static const Context* GetCurrentContext();
			static bool SetCurrentContext(const Context* context);

		protected:
			virtual bool Activate() const = 0;
			virtual void Desactivate() const = 0;
			virtual const Loader& GetLoader() = 0;
			void OnContextRelease();

			virtual bool ImplementFallback(const std::string_view& function);

			static void NotifyContextDestruction(Context* context);

			ContextParams m_params;

		private:
			void GL_APIENTRY HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) const;

			enum class FunctionIndex
			{
#define NAZARA_OPENGLRENDERER_FUNC(name, sig) name,
				NAZARA_OPENGLRENDERER_FOREACH_GLES_FUNC(NAZARA_OPENGLRENDERER_FUNC, NAZARA_OPENGLRENDERER_FUNC)
#undef NAZARA_OPENGLRENDERER_FUNC

				Count
			};

			struct State
			{
				struct Box
				{
					GLint x, y;
					GLsizei width, height;
				};

				struct TextureUnit
				{
					GLuint sampler = 0;
					std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> textureTargets = { 0 };
				};

				struct UniformBufferUnit
				{
					GLuint buffer = 0;
					GLintptr offset = 0;
					GLsizeiptr size = 0;
				};

				std::array<GLuint, UnderlyingCast(BufferTarget::Max) + 1> bufferTargets = { 0 };
				std::vector<TextureUnit> textureUnits;
				std::vector<UniformBufferUnit> uboUnits;
				Box scissorBox;
				Box viewport;
				GLuint boundProgram = 0;
				GLuint boundDrawFBO = 0;
				GLuint boundReadFBO = 0;
				GLuint boundVertexArray = 0;
				UInt32 currentTextureUnit = 0;
				RenderStates renderStates;
			};

			std::array<ExtensionStatus, UnderlyingCast(Extension::Max) + 1> m_extensionStatus;
			std::array<GLFunction, UnderlyingCast(FunctionIndex::Count)> m_originalFunctionPointer;
			std::unordered_set<std::string> m_supportedExtensions;
			OpenGLVaoCache m_vaoCache;
			const OpenGLDevice* m_device;
			mutable State m_state;
	};
}

#include <Nazara/OpenGLRenderer/Wrapper/Context.inl>

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX
#define INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX

#include <com/sun/star/awt/XWindow2.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/awt/XWindowListener.hpp>

#include <canvas/canvastools.hxx>
#include <canvas/base/graphicdevicebase.hxx>

/* Definition of BufferedGraphicDeviceBase class */

namespace canvas
{
    /** Helper template base class for XGraphicDevice implementations
        on windows.

        Use this base class if your target device is a
        window. Additionally to GraphicDeviceBase, this template
        provides an implementation of the awt::XWindowListener
        interface, to receive notifications about state changes of the
        associated window.

        @tpl Base
        Base class to use, most probably one of the
        WeakComponentImplHelperN templates with the appropriate
        interfaces. At least XGraphicDevice should be among them (why else
        would you use this template, then?). Base class must have an
        Base( const Mutex& ) constructor (like the
        WeakComponentImplHelperN templates have). As the very least,
        the base class must be derived from uno::XInterface, as some
        error reporting mechanisms rely on that.

        @tpl DeviceHelper
        Device helper implementation for the backend in question. This
        object will be held as a member of this template class, and
        basically gets forwarded all XGraphicDevice API calls that
        could not be handled generically.

        @tpl Mutex
        Lock strategy to use. Defaults to using the
        OBaseMutex-provided lock.  Everytime one of the methods is
        entered, an object of type Mutex is created with m_aMutex as
        the sole parameter, and destroyed again when the method scope
        is left.

        @tpl UnambiguousBase
        Optional unambiguous base class for XInterface of Base. It's
        sometimes necessary to specify this parameter, e.g. if Base
        derives from multiple UNO interface (were each provides its
        own version of XInterface, making the conversion ambiguous)
     */
    template< class Base,
              class DeviceHelper,
              class Mutex=::osl::MutexGuard,
              class UnambiguousBase=::com::sun::star::uno::XInterface > class BufferedGraphicDeviceBase :
        public GraphicDeviceBase< Base, DeviceHelper, Mutex, UnambiguousBase >
    {
    public:
        typedef GraphicDeviceBase< Base, DeviceHelper, Mutex, UnambiguousBase > BaseType;
        typedef BufferedGraphicDeviceBase OurType;
        typedef Mutex MutexType;

        BufferedGraphicDeviceBase() :
            mxWindow(),
            maBounds(),
            mbIsVisible( false ),
            mbIsTopLevel( false )
        {
            BaseType::maPropHelper.addProperties( PropertySetHelper::MakeMap
                                                  ("Window",
                                                   boost::bind(&OurType::getXWindow,
                                                               this)));
        }

        // XGraphicDevice
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBufferController > SAL_CALL getBufferController(  ) throw (::com::sun::star::uno::RuntimeException)
        {
            return this;
        }

        // XBufferController
        virtual ::sal_Int32 SAL_CALL createBuffers( ::sal_Int32 nBuffers ) throw (::com::sun::star::lang::IllegalArgumentException,
                                                                                ::com::sun::star::uno::RuntimeException)
        {
            tools::verifyRange( nBuffers, (sal_Int32)1 );

            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.createBuffers( nBuffers );
        }

        virtual void SAL_CALL destroyBuffers(  ) throw (::com::sun::star::uno::RuntimeException)
        {
            MutexType aGuard( BaseType::m_aMutex );

            BaseType::maDeviceHelper.destroyBuffers();
        }

        virtual ::sal_Bool SAL_CALL showBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException)
        {
            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.showBuffer( mbIsVisible, bUpdateAll );
        }

        virtual ::sal_Bool SAL_CALL switchBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException)
        {
            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.switchBuffer( mbIsVisible, bUpdateAll );
        }

        /** Set corresponding canvas window

            Use this method to set the window this canvas displays
            on. Comes in handy when the canvas needs to adapt size or
            output position to the changing window.

            Whenever the bounds of the window change, void
            notifySizeUpdate( const awt::Rectangle& rBounds )
            is called, with rBounds the window bound rect relative to
            the frame window.
         */
        void setWindow( const ::com::sun::star::uno::Reference<
                              ::com::sun::star::awt::XWindow2 >& rWindow )
        {
            if( mxWindow.is() )
                mxWindow->removeWindowListener( this );

            mxWindow = rWindow;

            if( mxWindow.is() )
            {
                mbIsVisible = mxWindow->isVisible();
                mbIsTopLevel =
                    ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTopWindow >(
                        mxWindow,
                        ::com::sun::star::uno::UNO_QUERY ).is();

                maBounds = transformBounds( mxWindow->getPosSize() );
                mxWindow->addWindowListener( this );
            }
        }

        ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 > getWindow() const
        {
            return mxWindow;
        }

        ::com::sun::star::uno::Any getXWindow() const
        {
            return ::com::sun::star::uno::makeAny(mxWindow);
        }

        virtual void disposeThis()
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            if( mxWindow.is() )
            {
                mxWindow->removeWindowListener(this);
                mxWindow.clear();
            }

            // pass on to base class
            BaseType::disposeThis();
        }

        ::com::sun::star::awt::Rectangle transformBounds( const ::com::sun::star::awt::Rectangle& rBounds )
        {
            // notifySizeUpdate's bounds are relative to the toplevel
            // window
            if( !mbIsTopLevel )
                return tools::getAbsoluteWindowRect(
                    rBounds,
                    mxWindow );
            else
                return ::com::sun::star::awt::Rectangle( 0,0,rBounds.Width,rBounds.Height );
        }

        void boundsChanged( const ::com::sun::star::awt::WindowEvent& e )
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            const ::com::sun::star::awt::Rectangle& rNewBounds(
                transformBounds(
                    ::com::sun::star::awt::Rectangle( e.X,
                                                      e.Y,
                                                      e.Width,
                                                      e.Height )));

            if( rNewBounds.X != maBounds.X ||
                rNewBounds.Y != maBounds.Y ||
                rNewBounds.Width != maBounds.Width ||
                rNewBounds.Height != maBounds.Height )
            {
                maBounds = rNewBounds;
                BaseType::maDeviceHelper.notifySizeUpdate( maBounds );
            }
        }

        // XWindowListener
        virtual void disposeEventSource( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            if( Source.Source == mxWindow )
                mxWindow.clear();

            BaseType::disposeEventSource(Source);
        }

        virtual void SAL_CALL windowResized( const ::com::sun::star::awt::WindowEvent& e ) throw (::com::sun::star::uno::RuntimeException)
        {
            boundsChanged( e );
        }

        virtual void SAL_CALL windowMoved( const ::com::sun::star::awt::WindowEvent& e ) throw (::com::sun::star::uno::RuntimeException)
        {
            boundsChanged( e );
        }

        virtual void SAL_CALL windowShown( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            mbIsVisible = true;
        }

        virtual void SAL_CALL windowHidden( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            mbIsVisible = false;
        }

    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 >  mxWindow;

        /// Current bounds of the owning Window
        ::com::sun::star::awt::Rectangle                                     maBounds;

        /// True, if the window this canvas is contained in, is visible
        bool                                                                 mbIsVisible;

    private:
        /// True, if the window this canvas is contained in, is a toplevel window
        bool                                                                 mbIsTopLevel;
    };
}

#endif // INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#1103730 Uncaught exception<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX
#define INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX

#include <com/sun/star/awt/XWindow2.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/awt/XWindowListener.hpp>

#include <canvas/canvastools.hxx>
#include <canvas/base/graphicdevicebase.hxx>

/* Definition of BufferedGraphicDeviceBase class */

namespace canvas
{
    /** Helper template base class for XGraphicDevice implementations
        on windows.

        Use this base class if your target device is a
        window. Additionally to GraphicDeviceBase, this template
        provides an implementation of the awt::XWindowListener
        interface, to receive notifications about state changes of the
        associated window.

        @tpl Base
        Base class to use, most probably one of the
        WeakComponentImplHelperN templates with the appropriate
        interfaces. At least XGraphicDevice should be among them (why else
        would you use this template, then?). Base class must have an
        Base( const Mutex& ) constructor (like the
        WeakComponentImplHelperN templates have). As the very least,
        the base class must be derived from uno::XInterface, as some
        error reporting mechanisms rely on that.

        @tpl DeviceHelper
        Device helper implementation for the backend in question. This
        object will be held as a member of this template class, and
        basically gets forwarded all XGraphicDevice API calls that
        could not be handled generically.

        @tpl Mutex
        Lock strategy to use. Defaults to using the
        OBaseMutex-provided lock.  Everytime one of the methods is
        entered, an object of type Mutex is created with m_aMutex as
        the sole parameter, and destroyed again when the method scope
        is left.

        @tpl UnambiguousBase
        Optional unambiguous base class for XInterface of Base. It's
        sometimes necessary to specify this parameter, e.g. if Base
        derives from multiple UNO interface (were each provides its
        own version of XInterface, making the conversion ambiguous)
     */
    template< class Base,
              class DeviceHelper,
              class Mutex=::osl::MutexGuard,
              class UnambiguousBase=::com::sun::star::uno::XInterface > class BufferedGraphicDeviceBase :
        public GraphicDeviceBase< Base, DeviceHelper, Mutex, UnambiguousBase >
    {
    public:
        typedef GraphicDeviceBase< Base, DeviceHelper, Mutex, UnambiguousBase > BaseType;
        typedef BufferedGraphicDeviceBase OurType;
        typedef Mutex MutexType;

        BufferedGraphicDeviceBase() :
            mxWindow(),
            maBounds(),
            mbIsVisible( false ),
            mbIsTopLevel( false )
        {
            BaseType::maPropHelper.addProperties( PropertySetHelper::MakeMap
                                                  ("Window",
                                                   boost::bind(&OurType::getXWindow,
                                                               this)));
        }

        // XGraphicDevice
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBufferController > SAL_CALL getBufferController(  ) throw (::com::sun::star::uno::RuntimeException)
        {
            return this;
        }

        // XBufferController
        virtual ::sal_Int32 SAL_CALL createBuffers( ::sal_Int32 nBuffers ) throw (::com::sun::star::lang::IllegalArgumentException,
                                                                                ::com::sun::star::uno::RuntimeException)
        {
            tools::verifyRange( nBuffers, (sal_Int32)1 );

            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.createBuffers( nBuffers );
        }

        virtual void SAL_CALL destroyBuffers(  ) throw (::com::sun::star::uno::RuntimeException)
        {
            MutexType aGuard( BaseType::m_aMutex );

            BaseType::maDeviceHelper.destroyBuffers();
        }

        virtual ::sal_Bool SAL_CALL showBuffer( ::sal_Bool bUpdateAll )
            throw (::com::sun::star::uno::RuntimeException,
                   std::exception)
        {
            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.showBuffer( mbIsVisible, bUpdateAll );
        }

        virtual ::sal_Bool SAL_CALL switchBuffer( ::sal_Bool bUpdateAll ) throw (::com::sun::star::uno::RuntimeException)
        {
            MutexType aGuard( BaseType::m_aMutex );

            return BaseType::maDeviceHelper.switchBuffer( mbIsVisible, bUpdateAll );
        }

        /** Set corresponding canvas window

            Use this method to set the window this canvas displays
            on. Comes in handy when the canvas needs to adapt size or
            output position to the changing window.

            Whenever the bounds of the window change, void
            notifySizeUpdate( const awt::Rectangle& rBounds )
            is called, with rBounds the window bound rect relative to
            the frame window.
         */
        void setWindow( const ::com::sun::star::uno::Reference<
                              ::com::sun::star::awt::XWindow2 >& rWindow )
        {
            if( mxWindow.is() )
                mxWindow->removeWindowListener( this );

            mxWindow = rWindow;

            if( mxWindow.is() )
            {
                mbIsVisible = mxWindow->isVisible();
                mbIsTopLevel =
                    ::com::sun::star::uno::Reference< ::com::sun::star::awt::XTopWindow >(
                        mxWindow,
                        ::com::sun::star::uno::UNO_QUERY ).is();

                maBounds = transformBounds( mxWindow->getPosSize() );
                mxWindow->addWindowListener( this );
            }
        }

        ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 > getWindow() const
        {
            return mxWindow;
        }

        ::com::sun::star::uno::Any getXWindow() const
        {
            return ::com::sun::star::uno::makeAny(mxWindow);
        }

        virtual void disposeThis()
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            if( mxWindow.is() )
            {
                mxWindow->removeWindowListener(this);
                mxWindow.clear();
            }

            // pass on to base class
            BaseType::disposeThis();
        }

        ::com::sun::star::awt::Rectangle transformBounds( const ::com::sun::star::awt::Rectangle& rBounds )
        {
            // notifySizeUpdate's bounds are relative to the toplevel
            // window
            if( !mbIsTopLevel )
                return tools::getAbsoluteWindowRect(
                    rBounds,
                    mxWindow );
            else
                return ::com::sun::star::awt::Rectangle( 0,0,rBounds.Width,rBounds.Height );
        }

        void boundsChanged( const ::com::sun::star::awt::WindowEvent& e )
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            const ::com::sun::star::awt::Rectangle& rNewBounds(
                transformBounds(
                    ::com::sun::star::awt::Rectangle( e.X,
                                                      e.Y,
                                                      e.Width,
                                                      e.Height )));

            if( rNewBounds.X != maBounds.X ||
                rNewBounds.Y != maBounds.Y ||
                rNewBounds.Width != maBounds.Width ||
                rNewBounds.Height != maBounds.Height )
            {
                maBounds = rNewBounds;
                BaseType::maDeviceHelper.notifySizeUpdate( maBounds );
            }
        }

        // XWindowListener
        virtual void disposeEventSource( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            if( Source.Source == mxWindow )
                mxWindow.clear();

            BaseType::disposeEventSource(Source);
        }

        virtual void SAL_CALL windowResized( const ::com::sun::star::awt::WindowEvent& e ) throw (::com::sun::star::uno::RuntimeException)
        {
            boundsChanged( e );
        }

        virtual void SAL_CALL windowMoved( const ::com::sun::star::awt::WindowEvent& e ) throw (::com::sun::star::uno::RuntimeException)
        {
            boundsChanged( e );
        }

        virtual void SAL_CALL windowShown( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            mbIsVisible = true;
        }

        virtual void SAL_CALL windowHidden( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException)
        {
            typename BaseType::MutexType aGuard( BaseType::m_aMutex );

            mbIsVisible = false;
        }

    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 >  mxWindow;

        /// Current bounds of the owning Window
        ::com::sun::star::awt::Rectangle                                     maBounds;

        /// True, if the window this canvas is contained in, is visible
        bool                                                                 mbIsVisible;

    private:
        /// True, if the window this canvas is contained in, is a toplevel window
        bool                                                                 mbIsTopLevel;
    };
}

#endif // INCLUDED_CANVAS_BASE_BUFFEREDGRAPHICDEVICEBASE_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/notifications/extension_welcome_notification.h"

#include "base/guid.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_delegate.h"
#include "ui/message_center/notification_types.h"

const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 14;

namespace {

class NotificationCallbacks
    : public message_center::NotificationDelegate {
 public:
  NotificationCallbacks(
      Profile* profile,
      const message_center::NotifierId notifier_id,
      const std::string& welcome_notification_id,
      ExtensionWelcomeNotification::Delegate* delegate)
      : profile_(profile),
        notifier_id_(notifier_id.type, notifier_id.id),
        welcome_notification_id_(welcome_notification_id),
        delegate_(delegate) {
  }

  // Overridden from NotificationDelegate:
  virtual void Display() OVERRIDE {}
  virtual void Error() OVERRIDE {}

  virtual void Close(bool by_user) OVERRIDE {
    if (by_user) {
      // Setting the preference here may cause the notification erasing
      // to reenter. Posting a task avoids this issue.
      delegate_->PostTask(
          FROM_HERE,
          base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
    }
  }

  virtual void Click() OVERRIDE {}
  virtual void ButtonClick(int index) OVERRIDE {
    if (index == 0) {
      OpenNotificationLearnMoreTab();
    } else if (index == 1) {
      DisableNotificationProvider();
      Close(true);
    } else {
      NOTREACHED();
    }
  }

 private:
  void MarkAsDismissed() {
    profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissedLocal,
                                     true);
  }

  void OpenNotificationLearnMoreTab() {
    chrome::NavigateParams params(
        profile_,
        GURL(chrome::kNotificationWelcomeLearnMoreURL),
        content::PAGE_TRANSITION_LINK);
    params.disposition = NEW_FOREGROUND_TAB;
    params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    chrome::Navigate(&params);
  }

  void DisableNotificationProvider() {
    message_center::Notifier notifier(notifier_id_, base::string16(), true);
    message_center::MessageCenter* message_center =
        delegate_->GetMessageCenter();
    message_center->DisableNotificationsByNotifier(notifier_id_);
    message_center->RemoveNotification(welcome_notification_id_, true);
    message_center->GetNotifierSettingsProvider()->SetNotifierEnabled(
        notifier, false);
  }

  virtual ~NotificationCallbacks() {}

  Profile* const profile_;

  const message_center::NotifierId notifier_id_;

  std::string welcome_notification_id_;

  // Weak ref owned by ExtensionWelcomeNotification.
  ExtensionWelcomeNotification::Delegate* const delegate_;

  DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
};

class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
 public:
  DefaultDelegate() {}

  virtual message_center::MessageCenter* GetMessageCenter() OVERRIDE {
    return g_browser_process->message_center();
  }

  virtual base::Time GetCurrentTime() OVERRIDE {
    return base::Time::Now();
  }

  virtual void PostTask(
      const tracked_objects::Location& from_here,
      const base::Closure& task) OVERRIDE {
    base::MessageLoop::current()->PostTask(from_here, task);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
};

}  // namespace

ExtensionWelcomeNotification::ExtensionWelcomeNotification(
    const std::string& extension_id,
    Profile* const profile,
    ExtensionWelcomeNotification::Delegate* const delegate)
    : notifier_id_(message_center::NotifierId::APPLICATION, extension_id),
      profile_(profile),
      delegate_(delegate) {
  welcome_notification_dismissed_pref_.Init(
      prefs::kWelcomeNotificationDismissed,
      profile_->GetPrefs(),
      base::Bind(
          &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
          base::Unretained(this)));
  welcome_notification_dismissed_local_pref_.Init(
      prefs::kWelcomeNotificationDismissedLocal,
      profile_->GetPrefs());
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile) {
  return Create(extension_id, profile, new DefaultDelegate()).Pass();
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile,
    Delegate* const delegate) {
  return scoped_ptr<ExtensionWelcomeNotification>(
      new ExtensionWelcomeNotification(extension_id, profile, delegate)).Pass();
}

ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
  if (delayed_notification_) {
    delayed_notification_.reset();
    PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
  } else {
    HideWelcomeNotification();
  }
}

void ExtensionWelcomeNotification::OnIsSyncingChanged() {
  DCHECK(delayed_notification_);
  PrefServiceSyncable* const pref_service_syncable =
      PrefServiceSyncable::FromProfile(profile_);
  if (pref_service_syncable->IsSyncing()) {
    pref_service_syncable->RemoveObserver(this);
    scoped_ptr<Notification> previous_notification(
        delayed_notification_.release());
    ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
  }
}

void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
    const Notification& notification) {
  if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
    PrefServiceSyncable* const pref_service_syncable =
        PrefServiceSyncable::FromProfile(profile_);
    if (pref_service_syncable->IsSyncing()) {
      PrefService* const pref_service = profile_->GetPrefs();
      if (!UserHasDismissedWelcomeNotification()) {
        const PopUpRequest pop_up_request =
            pref_service->GetBoolean(
                prefs::kWelcomeNotificationPreviouslyPoppedUp)
                ? POP_UP_HIDDEN
                : POP_UP_SHOWN;
        if (pop_up_request == POP_UP_SHOWN) {
          pref_service->SetBoolean(
              prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
        }

        if (IsWelcomeNotificationExpired()) {
          ExpireWelcomeNotification();
        } else {
          ShowWelcomeNotification(
              notification.display_source(), pop_up_request);
        }
      }
    } else {
      delayed_notification_.reset(new Notification(notification));
      pref_service_syncable->AddObserver(this);
    }
  }
}

// static
void ExtensionWelcomeNotification::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* prefs) {
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
                             false,
                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissedLocal,
                             false,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
                             false,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp,
                           0,
                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

message_center::MessageCenter*
ExtensionWelcomeNotification::GetMessageCenter() const {
  return delegate_->GetMessageCenter();
}

void ExtensionWelcomeNotification::ShowWelcomeNotification(
    const base::string16& display_source,
    const PopUpRequest pop_up_request) {
  message_center::ButtonInfo learn_more(
      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
  learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_NOTIFICATION_WELCOME_LEARN_MORE);
  message_center::ButtonInfo disable(
      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
  disable.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_NOTIFIER_BLOCK_BUTTON);

  message_center::RichNotificationData rich_notification_data;
  rich_notification_data.priority = 2;
  rich_notification_data.buttons.push_back(learn_more);
  rich_notification_data.buttons.push_back(disable);

  if (welcome_notification_id_.empty())
    welcome_notification_id_ = base::GenerateGUID();

  if (!welcome_notification_id_.empty()) {
    scoped_ptr<message_center::Notification> message_center_notification(
        new message_center::Notification(
            message_center::NOTIFICATION_TYPE_BASE_FORMAT,
            welcome_notification_id_,
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
            ui::ResourceBundle::GetSharedInstance().GetImageNamed(
                IDR_NOTIFICATION_WELCOME_ICON),
            display_source,
            notifier_id_,
            rich_notification_data,
            new NotificationCallbacks(
                profile_, notifier_id_, welcome_notification_id_,
                delegate_.get())));

    if (pop_up_request == POP_UP_HIDDEN)
      message_center_notification->set_shown_as_popup(true);

    GetMessageCenter()->AddNotification(message_center_notification.Pass());
    StartExpirationTimer();
  }
}

void ExtensionWelcomeNotification::HideWelcomeNotification() {
  if (!welcome_notification_id_.empty() &&
      GetMessageCenter()->HasNotification(welcome_notification_id_)) {
    GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
    StopExpirationTimer();
  }
}

bool ExtensionWelcomeNotification::UserHasDismissedWelcomeNotification() const {
  // This was previously a syncable preference; now it's per-machine.
  // Only the local pref will be written moving forward, but check for both so
  // users won't be double-toasted.
  bool shown_synced = profile_->GetPrefs()->GetBoolean(
      prefs::kWelcomeNotificationDismissed);
  bool shown_local = profile_->GetPrefs()->GetBoolean(
      prefs::kWelcomeNotificationDismissedLocal);
  return (shown_synced || shown_local);
}

void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
  if (UserHasDismissedWelcomeNotification()) {
    HideWelcomeNotification();
  }
}

void ExtensionWelcomeNotification::StartExpirationTimer() {
  if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
    base::Time expiration_timestamp = GetExpirationTimestamp();
    if (expiration_timestamp.is_null()) {
      SetExpirationTimestampFromNow();
      expiration_timestamp = GetExpirationTimestamp();
      DCHECK(!expiration_timestamp.is_null());
    }
    expiration_timer_.reset(
        new base::OneShotTimer<ExtensionWelcomeNotification>());
    expiration_timer_->Start(
        FROM_HERE,
        expiration_timestamp - delegate_->GetCurrentTime(),
        this,
        &ExtensionWelcomeNotification::ExpireWelcomeNotification);
  }
}

void ExtensionWelcomeNotification::StopExpirationTimer() {
  if (expiration_timer_) {
    expiration_timer_->Stop();
    expiration_timer_.reset();
  }
}

void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
  DCHECK(IsWelcomeNotificationExpired());
  profile_->GetPrefs()->SetBoolean(
      prefs::kWelcomeNotificationDismissedLocal, true);
  HideWelcomeNotification();
}

base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
  PrefService* const pref_service = profile_->GetPrefs();
  const int64 expiration_timestamp =
      pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
  return (expiration_timestamp == 0)
      ? base::Time()
      : base::Time::FromInternalValue(expiration_timestamp);
}

void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
  PrefService* const pref_service = profile_->GetPrefs();
  pref_service->SetInt64(
      prefs::kWelcomeNotificationExpirationTimestamp,
      (delegate_->GetCurrentTime() +
          base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
}

bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
  const base::Time expiration_timestamp = GetExpirationTimestamp();
  return !expiration_timestamp.is_null() &&
         (expiration_timestamp <= delegate_->GetCurrentTime());
}
<commit_msg>Fix Crash Due to Programmatic Dismissal of a Notification.<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/notifications/extension_welcome_notification.h"

#include "base/guid.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_delegate.h"
#include "ui/message_center/notification_types.h"

const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 14;

namespace {

class NotificationCallbacks
    : public message_center::NotificationDelegate {
 public:
  NotificationCallbacks(
      Profile* profile,
      const message_center::NotifierId notifier_id,
      const std::string& welcome_notification_id,
      ExtensionWelcomeNotification::Delegate* delegate)
      : profile_(profile),
        notifier_id_(notifier_id.type, notifier_id.id),
        welcome_notification_id_(welcome_notification_id),
        delegate_(delegate) {
  }

  // Overridden from NotificationDelegate:
  virtual void Display() OVERRIDE {}
  virtual void Error() OVERRIDE {}

  virtual void Close(bool by_user) OVERRIDE {
    if (by_user) {
      // Setting the preference here may cause the notification erasing
      // to reenter. Posting a task avoids this issue.
      delegate_->PostTask(
          FROM_HERE,
          base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
    }
  }

  virtual void Click() OVERRIDE {}
  virtual void ButtonClick(int index) OVERRIDE {
    if (index == 0) {
      OpenNotificationLearnMoreTab();
    } else if (index == 1) {
      DisableNotificationProvider();
      Close(true);
    } else {
      NOTREACHED();
    }
  }

 private:
  void MarkAsDismissed() {
    profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissedLocal,
                                     true);
  }

  void OpenNotificationLearnMoreTab() {
    chrome::NavigateParams params(
        profile_,
        GURL(chrome::kNotificationWelcomeLearnMoreURL),
        content::PAGE_TRANSITION_LINK);
    params.disposition = NEW_FOREGROUND_TAB;
    params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    chrome::Navigate(&params);
  }

  void DisableNotificationProvider() {
    message_center::Notifier notifier(notifier_id_, base::string16(), true);
    message_center::MessageCenter* message_center =
        delegate_->GetMessageCenter();
    message_center->DisableNotificationsByNotifier(notifier_id_);
    message_center->RemoveNotification(welcome_notification_id_, false);
    message_center->GetNotifierSettingsProvider()->SetNotifierEnabled(
        notifier, false);
  }

  virtual ~NotificationCallbacks() {}

  Profile* const profile_;

  const message_center::NotifierId notifier_id_;

  std::string welcome_notification_id_;

  // Weak ref owned by ExtensionWelcomeNotification.
  ExtensionWelcomeNotification::Delegate* const delegate_;

  DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
};

class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
 public:
  DefaultDelegate() {}

  virtual message_center::MessageCenter* GetMessageCenter() OVERRIDE {
    return g_browser_process->message_center();
  }

  virtual base::Time GetCurrentTime() OVERRIDE {
    return base::Time::Now();
  }

  virtual void PostTask(
      const tracked_objects::Location& from_here,
      const base::Closure& task) OVERRIDE {
    base::MessageLoop::current()->PostTask(from_here, task);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
};

}  // namespace

ExtensionWelcomeNotification::ExtensionWelcomeNotification(
    const std::string& extension_id,
    Profile* const profile,
    ExtensionWelcomeNotification::Delegate* const delegate)
    : notifier_id_(message_center::NotifierId::APPLICATION, extension_id),
      profile_(profile),
      delegate_(delegate) {
  welcome_notification_dismissed_pref_.Init(
      prefs::kWelcomeNotificationDismissed,
      profile_->GetPrefs(),
      base::Bind(
          &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
          base::Unretained(this)));
  welcome_notification_dismissed_local_pref_.Init(
      prefs::kWelcomeNotificationDismissedLocal,
      profile_->GetPrefs());
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile) {
  return Create(extension_id, profile, new DefaultDelegate()).Pass();
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile,
    Delegate* const delegate) {
  return scoped_ptr<ExtensionWelcomeNotification>(
      new ExtensionWelcomeNotification(extension_id, profile, delegate)).Pass();
}

ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
  if (delayed_notification_) {
    delayed_notification_.reset();
    PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
  } else {
    HideWelcomeNotification();
  }
}

void ExtensionWelcomeNotification::OnIsSyncingChanged() {
  DCHECK(delayed_notification_);
  PrefServiceSyncable* const pref_service_syncable =
      PrefServiceSyncable::FromProfile(profile_);
  if (pref_service_syncable->IsSyncing()) {
    pref_service_syncable->RemoveObserver(this);
    scoped_ptr<Notification> previous_notification(
        delayed_notification_.release());
    ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
  }
}

void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
    const Notification& notification) {
  if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
    PrefServiceSyncable* const pref_service_syncable =
        PrefServiceSyncable::FromProfile(profile_);
    if (pref_service_syncable->IsSyncing()) {
      PrefService* const pref_service = profile_->GetPrefs();
      if (!UserHasDismissedWelcomeNotification()) {
        const PopUpRequest pop_up_request =
            pref_service->GetBoolean(
                prefs::kWelcomeNotificationPreviouslyPoppedUp)
                ? POP_UP_HIDDEN
                : POP_UP_SHOWN;
        if (pop_up_request == POP_UP_SHOWN) {
          pref_service->SetBoolean(
              prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
        }

        if (IsWelcomeNotificationExpired()) {
          ExpireWelcomeNotification();
        } else {
          ShowWelcomeNotification(
              notification.display_source(), pop_up_request);
        }
      }
    } else {
      delayed_notification_.reset(new Notification(notification));
      pref_service_syncable->AddObserver(this);
    }
  }
}

// static
void ExtensionWelcomeNotification::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* prefs) {
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
                             false,
                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissedLocal,
                             false,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
                             false,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp,
                           0,
                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

message_center::MessageCenter*
ExtensionWelcomeNotification::GetMessageCenter() const {
  return delegate_->GetMessageCenter();
}

void ExtensionWelcomeNotification::ShowWelcomeNotification(
    const base::string16& display_source,
    const PopUpRequest pop_up_request) {
  message_center::ButtonInfo learn_more(
      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
  learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_NOTIFICATION_WELCOME_LEARN_MORE);
  message_center::ButtonInfo disable(
      l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
  disable.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_NOTIFIER_BLOCK_BUTTON);

  message_center::RichNotificationData rich_notification_data;
  rich_notification_data.priority = 2;
  rich_notification_data.buttons.push_back(learn_more);
  rich_notification_data.buttons.push_back(disable);

  if (welcome_notification_id_.empty())
    welcome_notification_id_ = base::GenerateGUID();

  if (!welcome_notification_id_.empty()) {
    scoped_ptr<message_center::Notification> message_center_notification(
        new message_center::Notification(
            message_center::NOTIFICATION_TYPE_BASE_FORMAT,
            welcome_notification_id_,
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
            ui::ResourceBundle::GetSharedInstance().GetImageNamed(
                IDR_NOTIFICATION_WELCOME_ICON),
            display_source,
            notifier_id_,
            rich_notification_data,
            new NotificationCallbacks(
                profile_, notifier_id_, welcome_notification_id_,
                delegate_.get())));

    if (pop_up_request == POP_UP_HIDDEN)
      message_center_notification->set_shown_as_popup(true);

    GetMessageCenter()->AddNotification(message_center_notification.Pass());
    StartExpirationTimer();
  }
}

void ExtensionWelcomeNotification::HideWelcomeNotification() {
  if (!welcome_notification_id_.empty() &&
      GetMessageCenter()->HasNotification(welcome_notification_id_)) {
    GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
    StopExpirationTimer();
  }
}

bool ExtensionWelcomeNotification::UserHasDismissedWelcomeNotification() const {
  // This was previously a syncable preference; now it's per-machine.
  // Only the local pref will be written moving forward, but check for both so
  // users won't be double-toasted.
  bool shown_synced = profile_->GetPrefs()->GetBoolean(
      prefs::kWelcomeNotificationDismissed);
  bool shown_local = profile_->GetPrefs()->GetBoolean(
      prefs::kWelcomeNotificationDismissedLocal);
  return (shown_synced || shown_local);
}

void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
  if (UserHasDismissedWelcomeNotification()) {
    HideWelcomeNotification();
  }
}

void ExtensionWelcomeNotification::StartExpirationTimer() {
  if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
    base::Time expiration_timestamp = GetExpirationTimestamp();
    if (expiration_timestamp.is_null()) {
      SetExpirationTimestampFromNow();
      expiration_timestamp = GetExpirationTimestamp();
      DCHECK(!expiration_timestamp.is_null());
    }
    expiration_timer_.reset(
        new base::OneShotTimer<ExtensionWelcomeNotification>());
    expiration_timer_->Start(
        FROM_HERE,
        expiration_timestamp - delegate_->GetCurrentTime(),
        this,
        &ExtensionWelcomeNotification::ExpireWelcomeNotification);
  }
}

void ExtensionWelcomeNotification::StopExpirationTimer() {
  if (expiration_timer_) {
    expiration_timer_->Stop();
    expiration_timer_.reset();
  }
}

void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
  DCHECK(IsWelcomeNotificationExpired());
  profile_->GetPrefs()->SetBoolean(
      prefs::kWelcomeNotificationDismissedLocal, true);
  HideWelcomeNotification();
}

base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
  PrefService* const pref_service = profile_->GetPrefs();
  const int64 expiration_timestamp =
      pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
  return (expiration_timestamp == 0)
      ? base::Time()
      : base::Time::FromInternalValue(expiration_timestamp);
}

void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
  PrefService* const pref_service = profile_->GetPrefs();
  pref_service->SetInt64(
      prefs::kWelcomeNotificationExpirationTimestamp,
      (delegate_->GetCurrentTime() +
          base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
}

bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
  const base::Time expiration_timestamp = GetExpirationTimestamp();
  return !expiration_timestamp.is_null() &&
         (expiration_timestamp <= delegate_->GetCurrentTime());
}
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/hlo_domain_isolator.h"

#include "tensorflow/compiler/xla/map_util.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_graph_dumper.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/types.h"

namespace xla {

namespace {

StatusOr<bool> RunInternal(HloModule* module,
                           HloDomainIsolator::DomainCreator* creator) {
  int64 added_domains = 0;
  for (HloComputation* computation : module->computations()) {
    // Walk in post order and place all the required kDomain instructions.
    for (HloInstruction* instruction :
         computation->MakeInstructionPostOrder()) {
      if (instruction->opcode() == HloOpcode::kDomain) {
        continue;
      }
      for (HloInstruction* operand : instruction->unique_operands()) {
        // When applying multiple domains, we could end up stacking more than
        // one in one edge, so here we want to build the effective
        // (kDomain-less) instruction->operand edge.
        HloInstruction* root = operand;
        while (root->opcode() == HloOpcode::kDomain) {
          root = root->mutable_operand(0);
        }
        // Check whether a kDomain is necessary between instruction and operand.
        HloInstruction* domain = (*creator)(instruction, root, operand);
        if (domain != nullptr) {
          VLOG(4) << "New domain: " << domain->ToString();
          TF_RETURN_IF_ERROR(operand->ReplaceUseWith(instruction, domain));
          ++added_domains;
        }
      }
    }
  }
  VLOG(3) << "Added " << added_domains << " kDomain instructions";
  return added_domains > 0;
}

}  // namespace

HloDomainIsolator::HloDomainIsolator(DomainCreatorFactory creator_factory)
    : creator_factory_(std::move(creator_factory)) {}

StatusOr<bool> HloDomainIsolator::Run(HloModule* module) {
  DomainCreator creator = creator_factory_();
  return RunInternal(module, &creator);
}

}  // namespace xla
<commit_msg>Improve performance of domain isolator<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/hlo_domain_isolator.h"

#include "tensorflow/compiler/xla/map_util.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_graph_dumper.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/types.h"

namespace xla {

namespace {

StatusOr<bool> RunInternal(HloModule* module,
                           HloDomainIsolator::DomainCreator* creator) {
  int64 added_domains = 0;
  for (HloComputation* computation : module->computations()) {
    // Walk in post order and place all the required kDomain instructions.
    for (HloInstruction* instruction :
         computation->MakeInstructionPostOrder()) {
      if (instruction->opcode() == HloOpcode::kDomain) {
        continue;
      }
      for (HloInstruction* operand : instruction->unique_operands()) {
        // When applying multiple domains, we could end up stacking more than
        // one in one edge, so here we want to build the effective
        // (kDomain-less) instruction->operand edge.
        HloInstruction* root = operand;
        while (root->opcode() == HloOpcode::kDomain) {
          root = root->mutable_operand(0);
        }
        // Check whether a kDomain is necessary between instruction and operand.
        HloInstruction* domain = (*creator)(instruction, root, operand);
        if (domain != nullptr) {
          VLOG(4) << "New domain: " << domain->ToString();
          // Call ReplaceUseWithDifferentShape even though the shapes are
          // expected to match to avoid an expensive shape check between the
          // original and the new instruction.
          TF_RETURN_IF_ERROR(
              operand->ReplaceUseWithDifferentShape(instruction, domain));
          ++added_domains;
        }
      }
    }
  }
  VLOG(3) << "Added " << added_domains << " kDomain instructions";
  return added_domains > 0;
}

}  // namespace

HloDomainIsolator::HloDomainIsolator(DomainCreatorFactory creator_factory)
    : creator_factory_(std::move(creator_factory)) {}

StatusOr<bool> HloDomainIsolator::Run(HloModule* module) {
  DomainCreator creator = creator_factory_();
  return RunInternal(module, &creator);
}

}  // namespace xla
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <iostream>
#include <math.h>
#include "matrix.h"
#include "field2.h"
#include "h5out.h"

using namespace std;

int get_direction(vector<int> p1, vector<int> p2) {
    if (p1[0] == p2[0])
        return 1;
    else if (p1[1] == p2[1])
        return 0;
    else
        return 2;
}

void monitor::set_F(Field2D *newF) {
    F = newF;
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double *freq, int N): monitor(name,freq,N), p1(p1), p2(p2) {
    F = nullptr;
    dir = get_direction(p1, p2);
    length = p2[dir] - p1[dir] + 1;
    prevE = new double[length];
    rE = matrix<double>(new double[N*length], length, N);
    iE = matrix<double>(new double[N*length], length, N);
    rH = matrix<double>(new double[N*length], length, N);
    iH = matrix<double>(new double[N*length], length, N);
    for (int i = 0; i != length; i++) {
        prevE[i] = 0;
        for (int j = 0; j!= N; j++) {
            rE[i][j] = 0;
            iE[i][j] = 0;
            rH[i][j] = 0;
            iH[i][j] = 0;
        }
    }
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double fmin, double fmax, int N):
            surface_monitor(name, p1, p2, nullptr, N) {
    freq = new double[N];
    for (int i = 0; i != N; i ++) {
        freq[i] = fmin + (fmax-fmin)/(N-1.0)*i;
    }
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double f):
            surface_monitor(name, p1, p2, nullptr, 1) {
    freq = new double[1];
    freq[0] = f;
}

void surface_monitor::update() {
    matrix<double> *Hfield;
    if (dir == 0)
        Hfield = &F->Hx;
    if (dir == 1)
        Hfield = &F->Hy;

    int a = p1[0];
    int b = p1[1];
    double E, H;
    //this if check could be done outside the for loop somehow
    for (int i = 0; i != length; i++) {
        if (dir == 0) {
            a = p1[0] + i;
            E = (prevE[i] + F->Ez[a][b])/2;
            H = ((*Hfield)[a][b] + (*Hfield)[a-1][b-1])/2;
        }
        else if (dir == 1) {
            b = p1[1] + i;
            E = (prevE[i] + F->Ez[a][b])/2;
            H = ((*Hfield)[a][b] + (*Hfield)[a][b-1])/2;
        }
        prevE[i] = F->Ez[a][b]/2;

        for (int j = 0; j != N; j++) {
            rE[i][j] += E*cos(2*M_PI*freq[j]*F->t);
            iE[i][j] += E*sin(2*M_PI*freq[j]*F->t);
            rH[i][j] += H*cos(2*M_PI*freq[j]*F->t);
            iH[i][j] += H*sin(2*M_PI*freq[j]*F->t);
        }
    }
}

void surface_monitor::write(string filename, bool extendable) {
    double *S = new double[N];
    for (int i = 0; i != N; i++)
        S[i] = 0;

    for (int j = 0; j != N; j++) {
        for (int i = 0; i != length; i++) {
            S[j] += rE[i][j]*rH[i][j] + iE[i][j]*iH[i][j];
        }
        S[j] *= F->dx;
    }

    F->write_monitor(filename, name, S, N, extendable);
    delete[] S;
}

//none of this below actually works
//Consider the following: box_monitor doesn't call surface_monitor, but the code used in surface_monitor
//         can be externalized so that both can use it
//For corners, first study using 4 surface_monitors directly

box_monitor::box_monitor(string name, vector<int> p1, vector<int> p2, double *freq, int N):
                monitor(name, freq, N) {
    monitors = new surface_monitor[4];
    monitors[0] = surface_monitor(name + "_1", p1, {p2[0], p1[1]}, freq, N);
    monitors[1] = surface_monitor(name + "_2", {p2[0], p1[1]}, p2, freq, N);
    monitors[2] = surface_monitor(name + "_3", {p1[1], p2[0]}, p2, freq, N);
    monitors[3] = surface_monitor(name + "_4", p1, {p1[1], p2[0]}, freq, N);
}

box_monitor::box_monitor(std::string name, std::vector<int> p1, std::vector<int> p2, double fmin, double fmax, int N):
            box_monitor(name, p1 p2, nullptr, N) {
    freq = new double[N];
    for (int i = 0; i != N; i ++) {
        freq[i] = fmin + (fmax-fmin)/(N-1.0)*i;
    }
}

box_monitor::box_monitor(std::string name, std::vector<int> p1, std::vector<int> p2, double f);
            box_monitor(name, p1 p2, nullptr, 1) {
    freq = new double[1];
    freq[0] = f;
}

<commit_msg>fixed another crucial oneline bug in monitor<commit_after>#include <vector>
#include <string>
#include <iostream>
#include <math.h>
#include "matrix.h"
#include "field2.h"
#include "h5out.h"

using namespace std;

int get_direction(vector<int> p1, vector<int> p2) {
    if (p1[0] == p2[0])
        return 1;
    else if (p1[1] == p2[1])
        return 0;
    else
        return 2;
}

void monitor::set_F(Field2D *newF) {
    F = newF;
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double *freq, int N): monitor(name,freq,N), p1(p1), p2(p2) {
    F = nullptr;
    dir = get_direction(p1, p2);
    length = p2[dir] - p1[dir] + 1;
    prevE = new double[length];
    rE = matrix<double>(new double[N*length], length, N);
    iE = matrix<double>(new double[N*length], length, N);
    rH = matrix<double>(new double[N*length], length, N);
    iH = matrix<double>(new double[N*length], length, N);
    for (int i = 0; i != length; i++) {
        prevE[i] = 0;
        for (int j = 0; j!= N; j++) {
            rE[i][j] = 0;
            iE[i][j] = 0;
            rH[i][j] = 0;
            iH[i][j] = 0;
        }
    }
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double fmin, double fmax, int N):
            surface_monitor(name, p1, p2, nullptr, N) {
    freq = new double[N];
    for (int i = 0; i != N; i ++) {
        freq[i] = fmin + (fmax-fmin)/(N-1.0)*i;
    }
}

surface_monitor::surface_monitor(string name, vector<int> p1, vector<int> p2, double f):
            surface_monitor(name, p1, p2, nullptr, 1) {
    freq = new double[1];
    freq[0] = f;
}

void surface_monitor::update() {
    matrix<double> *Hfield;
    if (dir == 0)
        Hfield = &F->Hx;
    if (dir == 1)
        Hfield = &F->Hy;

    int a = p1[0];
    int b = p1[1];
    double E, H;
    //this if check could be done outside the for loop somehow
    for (int i = 0; i != length; i++) {
        if (dir == 0) {
            a = p1[0] + i;
            E = (prevE[i] + F->Ez[a][b])/2;
            H = ((*Hfield)[a][b] + (*Hfield)[a-1][b-1])/2;
        }
        else if (dir == 1) {
            b = p1[1] + i;
            E = (prevE[i] + F->Ez[a][b])/2;
            H = ((*Hfield)[a][b] + (*Hfield)[a][b-1])/2;
        }
        prevE[i] = F->Ez[a][b];

        for (int j = 0; j != N; j++) {
            rE[i][j] += E*cos(2*M_PI*freq[j]*F->t);
            iE[i][j] += E*sin(2*M_PI*freq[j]*F->t);
            rH[i][j] += H*cos(2*M_PI*freq[j]*F->t);
            iH[i][j] += H*sin(2*M_PI*freq[j]*F->t);
        }
    }
}

void surface_monitor::write(string filename, bool extendable) {
    double *S = new double[N];
    for (int i = 0; i != N; i++)
        S[i] = 0;

    for (int j = 0; j != N; j++) {
        for (int i = 0; i != length; i++) {
            S[j] += rE[i][j]*rH[i][j] + iE[i][j]*iH[i][j];
        }
        S[j] *= F->dx;
    }

    F->write_monitor(filename, name, S, N, extendable);
    delete[] S;
}

//none of this below actually works
//Consider the following: box_monitor doesn't call surface_monitor, but the code used in surface_monitor
//         can be externalized so that both can use it
//For corners, first study using 4 surface_monitors directly

box_monitor::box_monitor(string name, vector<int> p1, vector<int> p2, double *freq, int N):
                monitor(name, freq, N) {
    monitors = new surface_monitor[4];
    monitors[0] = surface_monitor(name + "_1", p1, {p2[0], p1[1]}, freq, N);
    monitors[1] = surface_monitor(name + "_2", {p2[0], p1[1]}, p2, freq, N);
    monitors[2] = surface_monitor(name + "_3", {p1[1], p2[0]}, p2, freq, N);
    monitors[3] = surface_monitor(name + "_4", p1, {p1[1], p2[0]}, freq, N);
}

box_monitor::box_monitor(std::string name, std::vector<int> p1, std::vector<int> p2, double fmin, double fmax, int N):
            box_monitor(name, p1 p2, nullptr, N) {
    freq = new double[N];
    for (int i = 0; i != N; i ++) {
        freq[i] = fmin + (fmax-fmin)/(N-1.0)*i;
    }
}

box_monitor::box_monitor(std::string name, std::vector<int> p1, std::vector<int> p2, double f);
            box_monitor(name, p1 p2, nullptr, 1) {
    freq = new double[1];
    freq[0] = f;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_RENDER_PATTERN_HPP
#define MAPNIK_RENDER_PATTERN_HPP

#include <mapnik/image.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/renderer_common.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/util/const_rendering_buffer.hpp>
#include <mapnik/marker_helpers.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h"
#include "agg_color_gray.h"
#include "agg_scanline_u.h"
#include "agg_image_accessors.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#pragma GCC diagnostic pop

namespace mapnik {

template <typename Symbolizer, typename Rasterizer>
struct common_pattern_process_visitor
{
    using image_type = image_rgba8;

    common_pattern_process_visitor(Rasterizer & ras,
                                   renderer_common const & common,
                                   Symbolizer const & sym,
                                   feature_impl const & feature)
        : ras_(ras),
          common_(common),
          sym_(sym),
          feature_(feature),
          spacing_(get<value_double>(sym_, keys::spacing)),
          lacing_(get<pattern_lacing_mode_enum>(sym_, keys::lacing))
    {
    }

    image_type operator() (marker_null const &) const
    {
        throw std::runtime_error("This should not have been reached.");
    }

    template <typename Marker>
    image_type operator() (Marker const & marker) const
    {
        box2d<double> bbox(marker.bounding_box());
        agg::trans_affine tr(transform(bbox));

        if (bbox.width() < 1.0 || bbox.height() < 1.0)
        {
            throw std::runtime_error("Pattern image smaller than one pixel");
        }

        if (lacing_ == PATTERN_LACING_MODE_ALTERNATING_GRID)
        {
            return render_pattern_alternating(ras_, marker, bbox, tr);
        }
        return render_pattern(ras_, marker, bbox, tr);
    }

private:
    agg::trans_affine transform(box2d<double> & bbox) const
    {
        agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_);
        auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
        if (image_transform) evaluate_transform(tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
        bbox *= tr;
        coord<double, 2> c = bbox.center();
        agg::trans_affine mtx = agg::trans_affine_translation(
            0.5 * bbox.width() - c.x,
            0.5 * bbox.height() - c.y);
        return tr * mtx;
    }

    image_rgba8 render_pattern(rasterizer & ras,
                               marker_svg const & marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::scanline_u8 sl;

        image_rgba8 image(bbox.width() + spacing_, bbox.height() + spacing_);
        agg::rendering_buffer buf(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        svg_storage_type & svg = *marker.get_data();
        svg_attribute_type const & svg_attributes = svg.attributes();
        svg_attribute_type custom_attributes;
        bool use_custom_attributes = push_explicit_style(
            svg_attributes, custom_attributes, sym_, feature_, common_.vars_);
        svg_attribute_type const & used_attributes = use_custom_attributes ?
            custom_attributes : svg_attributes;

        svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(svg.source());
        svg::svg_path_adapter svg_path(stl_storage);
        using renderer_type = svg::svg_renderer_agg<svg::svg_path_adapter,
            agg::pod_bvector<svg::path_attributes>, renderer_solid, pixfmt>;
        renderer_type svg_renderer(svg_path, used_attributes);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        return image;
    }

    image_rgba8 render_pattern(rasterizer & ras,
                               marker_rgba8 const& marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer = agg::renderer_scanline_aa_solid<renderer_base>;

        image_rgba8 image(bbox.width() + spacing_, bbox.height() + spacing_);
        agg::rendering_buffer buf_out(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf_out(buf_out);
        renderer_base rb(pixf_out);
        renderer r(rb);

        using const_rendering_buffer = util::rendering_buffer<image_rgba8>;
        using pixfmt_in = agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32_pre, const_rendering_buffer, agg::pixel32_type>;

        image_rgba8 const& src = marker.get_data();
        const_rendering_buffer buf_in(src);
        pixfmt_in pixf(buf_in);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        tr.invert();

        using interpolator_type = agg::span_interpolator_linear<>;
        interpolator_type interpolator(tr);

        agg::span_allocator<agg::rgba8> sa;

        agg::image_filter_lut filter;
        filter.calculate(agg::image_filter_bilinear(), true);

        using img_accessor_type = agg::image_accessor_clone<pixfmt_in>;
        using span_gen_type = agg::span_image_resample_rgba_affine<img_accessor_type>;
        img_accessor_type ia(pixf);
        span_gen_type sg(ia, interpolator, filter);

        agg::scanline_u8 sl;
        ras.move_to_d(0, 0);
        ras.line_to_d(image.width(), 0);
        ras.line_to_d(image.width(), image.height());
        ras.line_to_d(0, image.height());

        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        return image;
    }

    image_rgba8 render_pattern_alternating(rasterizer & ras,
                               marker_svg const & marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::scanline_u8 sl;

        image_rgba8 image(bbox.width() + spacing_, (bbox.height() + spacing_) * 2.0);
        agg::rendering_buffer buf(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        svg_storage_type & svg = *marker.get_data();
        svg_attribute_type const & svg_attributes = svg.attributes();
        svg_attribute_type custom_attributes;
        bool use_custom_attributes = push_explicit_style(
            svg_attributes, custom_attributes, sym_, feature_, common_.vars_);
        svg_attribute_type const & used_attributes = use_custom_attributes ?
            custom_attributes : svg_attributes;

        svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(svg.source());
        svg::svg_path_adapter svg_path(stl_storage);
        using renderer_type = svg::svg_renderer_agg<svg::svg_path_adapter,
            agg::pod_bvector<svg::path_attributes>, renderer_solid, pixfmt>;
        renderer_type svg_renderer(svg_path, used_attributes);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        tr.translate(-(bbox.width() / 2.0 + spacing_ / 2.0), bbox.height() + spacing_);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        tr.translate(bbox.width() + spacing_, 0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        return image;
    }

    image_rgba8 render_pattern_alternating(rasterizer & ras,
                               marker_rgba8 const& marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer = agg::renderer_scanline_aa_solid<renderer_base>;

        image_rgba8 image(bbox.width() + spacing_, (bbox.height() + spacing_) * 2.0);
        agg::rendering_buffer buf_out(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf_out(buf_out);
        renderer_base rb(pixf_out);
        renderer r(rb);

        using const_rendering_buffer = util::rendering_buffer<image_rgba8>;
        using pixfmt_in = agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32_pre, const_rendering_buffer, agg::pixel32_type>;

        image_rgba8 const& src = marker.get_data();
        const_rendering_buffer buf_in(src);
        pixfmt_in pixf(buf_in);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        tr.invert();

        using interpolator_type = agg::span_interpolator_linear<>;
        interpolator_type interpolator(tr);

        agg::span_allocator<agg::rgba8> sa;

        agg::image_filter_lut filter;
        filter.calculate(agg::image_filter_bilinear(), true);

        using img_accessor_type = agg::image_accessor_clone<pixfmt_in>;
        using span_gen_type = agg::span_image_resample_rgba_affine<img_accessor_type>;
        img_accessor_type ia(pixf);
        span_gen_type sg(ia, interpolator, filter);

        agg::scanline_u8 sl;
        ras.move_to_d(0, 0);
        ras.line_to_d(image.width(), 0);
        ras.line_to_d(image.width(), image.height());
        ras.line_to_d(0, image.height());

        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        tr.invert();
        tr.translate(-(bbox.width() / 2.0 + spacing_ / 2.0), bbox.height() + spacing_);
        tr.invert();
        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        tr.invert();
        tr.translate(bbox.width() + spacing_, 0);
        tr.invert();
        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        return image;
    }

    Rasterizer & ras_;
    renderer_common const & common_;
    Symbolizer const & sym_;
    feature_impl const & feature_;
    const value_double spacing_;
    const pattern_lacing_mode_enum lacing_;
};

} // namespace mapnik

#endif // MAPNIK_RENDER_PATTERN_HPP
<commit_msg>do not throw during rendering<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_RENDER_PATTERN_HPP
#define MAPNIK_RENDER_PATTERN_HPP

#include <mapnik/image.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/renderer_common.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_renderer_agg.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/util/const_rendering_buffer.hpp>
#include <mapnik/marker_helpers.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore_agg.hpp>
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h"
#include "agg_color_gray.h"
#include "agg_scanline_u.h"
#include "agg_image_accessors.h"
#include "agg_span_image_filter_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#pragma GCC diagnostic pop

namespace mapnik {

template <typename Symbolizer, typename Rasterizer>
struct common_pattern_process_visitor
{
    using image_type = image_rgba8;

    common_pattern_process_visitor(Rasterizer & ras,
                                   renderer_common const & common,
                                   Symbolizer const & sym,
                                   feature_impl const & feature)
        : ras_(ras),
          common_(common),
          sym_(sym),
          feature_(feature),
          spacing_(get<value_double>(sym_, keys::spacing)),
          lacing_(get<pattern_lacing_mode_enum>(sym_, keys::lacing))
    {
    }

    image_type operator() (marker_null const &) const
    {
        throw std::runtime_error("This should not have been reached.");
    }

    template <typename Marker>
    image_type operator() (Marker const & marker) const
    {
        box2d<double> bbox(marker.bounding_box());
        agg::trans_affine tr(transform(bbox));

        if (bbox.width() < 1.0 || bbox.height() < 1.0)
        {
            MAPNIK_LOG_ERROR(common_pattern_process_visitor) << "Pattern image smaller than one pixel";
        }

        if (lacing_ == PATTERN_LACING_MODE_ALTERNATING_GRID)
        {
            return render_pattern_alternating(ras_, marker, bbox, tr);
        }
        return render_pattern(ras_, marker, bbox, tr);
    }

private:
    agg::trans_affine transform(box2d<double> & bbox) const
    {
        agg::trans_affine tr = agg::trans_affine_scaling(common_.scale_factor_);
        auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
        if (image_transform) evaluate_transform(tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
        bbox *= tr;
        coord<double, 2> c = bbox.center();
        agg::trans_affine mtx = agg::trans_affine_translation(
            0.5 * bbox.width() - c.x,
            0.5 * bbox.height() - c.y);
        return tr * mtx;
    }

    image_rgba8 render_pattern(rasterizer & ras,
                               marker_svg const & marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::scanline_u8 sl;

        image_rgba8 image(bbox.width() + spacing_, bbox.height() + spacing_);
        agg::rendering_buffer buf(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        svg_storage_type & svg = *marker.get_data();
        svg_attribute_type const & svg_attributes = svg.attributes();
        svg_attribute_type custom_attributes;
        bool use_custom_attributes = push_explicit_style(
            svg_attributes, custom_attributes, sym_, feature_, common_.vars_);
        svg_attribute_type const & used_attributes = use_custom_attributes ?
            custom_attributes : svg_attributes;

        svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(svg.source());
        svg::svg_path_adapter svg_path(stl_storage);
        using renderer_type = svg::svg_renderer_agg<svg::svg_path_adapter,
            agg::pod_bvector<svg::path_attributes>, renderer_solid, pixfmt>;
        renderer_type svg_renderer(svg_path, used_attributes);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        return image;
    }

    image_rgba8 render_pattern(rasterizer & ras,
                               marker_rgba8 const& marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer = agg::renderer_scanline_aa_solid<renderer_base>;

        image_rgba8 image(bbox.width() + spacing_, bbox.height() + spacing_);
        agg::rendering_buffer buf_out(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf_out(buf_out);
        renderer_base rb(pixf_out);
        renderer r(rb);

        using const_rendering_buffer = util::rendering_buffer<image_rgba8>;
        using pixfmt_in = agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32_pre, const_rendering_buffer, agg::pixel32_type>;

        image_rgba8 const& src = marker.get_data();
        const_rendering_buffer buf_in(src);
        pixfmt_in pixf(buf_in);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        tr.invert();

        using interpolator_type = agg::span_interpolator_linear<>;
        interpolator_type interpolator(tr);

        agg::span_allocator<agg::rgba8> sa;

        agg::image_filter_lut filter;
        filter.calculate(agg::image_filter_bilinear(), true);

        using img_accessor_type = agg::image_accessor_clone<pixfmt_in>;
        using span_gen_type = agg::span_image_resample_rgba_affine<img_accessor_type>;
        img_accessor_type ia(pixf);
        span_gen_type sg(ia, interpolator, filter);

        agg::scanline_u8 sl;
        ras.move_to_d(0, 0);
        ras.line_to_d(image.width(), 0);
        ras.line_to_d(image.width(), image.height());
        ras.line_to_d(0, image.height());

        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        return image;
    }

    image_rgba8 render_pattern_alternating(rasterizer & ras,
                               marker_svg const & marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer_solid = agg::renderer_scanline_aa_solid<renderer_base>;
        agg::scanline_u8 sl;

        image_rgba8 image(bbox.width() + spacing_, (bbox.height() + spacing_) * 2.0);
        agg::rendering_buffer buf(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf(buf);
        renderer_base renb(pixf);

        svg_storage_type & svg = *marker.get_data();
        svg_attribute_type const & svg_attributes = svg.attributes();
        svg_attribute_type custom_attributes;
        bool use_custom_attributes = push_explicit_style(
            svg_attributes, custom_attributes, sym_, feature_, common_.vars_);
        svg_attribute_type const & used_attributes = use_custom_attributes ?
            custom_attributes : svg_attributes;

        svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(svg.source());
        svg::svg_path_adapter svg_path(stl_storage);
        using renderer_type = svg::svg_renderer_agg<svg::svg_path_adapter,
            agg::pod_bvector<svg::path_attributes>, renderer_solid, pixfmt>;
        renderer_type svg_renderer(svg_path, used_attributes);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        tr.translate(-(bbox.width() / 2.0 + spacing_ / 2.0), bbox.height() + spacing_);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        tr.translate(bbox.width() + spacing_, 0);
        svg_renderer.render(ras, sl, renb, tr, 1.0, bbox);
        return image;
    }

    image_rgba8 render_pattern_alternating(rasterizer & ras,
                               marker_rgba8 const& marker,
                               box2d<double> const & bbox,
                               agg::trans_affine tr) const
    {
        using pixfmt = agg::pixfmt_rgba32_pre;
        using renderer_base = agg::renderer_base<pixfmt>;
        using renderer = agg::renderer_scanline_aa_solid<renderer_base>;

        image_rgba8 image(bbox.width() + spacing_, (bbox.height() + spacing_) * 2.0);
        agg::rendering_buffer buf_out(image.bytes(), image.width(), image.height(), image.row_size());
        pixfmt pixf_out(buf_out);
        renderer_base rb(pixf_out);
        renderer r(rb);

        using const_rendering_buffer = util::rendering_buffer<image_rgba8>;
        using pixfmt_in = agg::pixfmt_alpha_blend_rgba<agg::blender_rgba32_pre, const_rendering_buffer, agg::pixel32_type>;

        image_rgba8 const& src = marker.get_data();
        const_rendering_buffer buf_in(src);
        pixfmt_in pixf(buf_in);

        tr.translate(spacing_ / 2.0, spacing_ / 2.0);
        tr.invert();

        using interpolator_type = agg::span_interpolator_linear<>;
        interpolator_type interpolator(tr);

        agg::span_allocator<agg::rgba8> sa;

        agg::image_filter_lut filter;
        filter.calculate(agg::image_filter_bilinear(), true);

        using img_accessor_type = agg::image_accessor_clone<pixfmt_in>;
        using span_gen_type = agg::span_image_resample_rgba_affine<img_accessor_type>;
        img_accessor_type ia(pixf);
        span_gen_type sg(ia, interpolator, filter);

        agg::scanline_u8 sl;
        ras.move_to_d(0, 0);
        ras.line_to_d(image.width(), 0);
        ras.line_to_d(image.width(), image.height());
        ras.line_to_d(0, image.height());

        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        tr.invert();
        tr.translate(-(bbox.width() / 2.0 + spacing_ / 2.0), bbox.height() + spacing_);
        tr.invert();
        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        tr.invert();
        tr.translate(bbox.width() + spacing_, 0);
        tr.invert();
        agg::render_scanlines_aa(ras, sl, rb, sa, sg);

        return image;
    }

    Rasterizer & ras_;
    renderer_common const & common_;
    Symbolizer const & sym_;
    feature_impl const & feature_;
    const value_double spacing_;
    const pattern_lacing_mode_enum lacing_;
};

} // namespace mapnik

#endif // MAPNIK_RENDER_PATTERN_HPP
<|endoftext|>