<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>

#ifdef CORRADE_TARGET_APPLE
#include <Magnum/Platform/WindowlessCglApplication.h>
#elif defined(CORRADE_TARGET_UNIX)
#include <Magnum/Platform/WindowlessGlxApplication.h>
#elif defined(CORRADE_TARGET_WINDOWS)
#include <Magnum/Platform/WindowlessWglApplication.h>
#else
#error no windowless application available on this platform
#endif

#include <Magnum/Buffer.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Image.h>
#include <Magnum/Mesh.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/RenderbufferFormat.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/Primitives/Square.h>
#include <Magnum/Primitives/Circle.h>
#include <Magnum/Primitives/Icosphere.h>
#include <Magnum/Primitives/UVSphere.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/MeshVisualizer.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Shaders/VertexColor.h>
#include <Magnum/Shaders/Vector.h>
#include <Magnum/Shaders/DistanceFieldVector.h>
#include <Magnum/Trade/AbstractImageConverter.h>
#include <Magnum/Trade/ImageData.h>
#include <Magnum/Trade/MeshData2D.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Renderer.h>
#include <Magnum/ColorFormat.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>

#include "configure.h"

using namespace Magnum;

struct ShaderVisualizer: Platform::WindowlessApplication {
    using Platform::WindowlessApplication::WindowlessApplication;

    int exec() override;

    std::string phong();
    std::string meshVisualizer();
    std::string flat();
    std::string vertexColor();

    std::string vector();
    std::string distanceFieldVector();

    std::unique_ptr<Trade::AbstractImporter> _importer;
};

namespace {
    constexpr const Vector2i ImageSize{256};
}

int ShaderVisualizer::exec() {
    PluginManager::Manager<Trade::AbstractImageConverter> converterManager{MAGNUM_PLUGINS_IMAGECONVERTER_DIR};
    std::unique_ptr<Trade::AbstractImageConverter> converter = converterManager.loadAndInstantiate("PngImageConverter");
    if(!converter) {
        Error() << "Cannot load image converter plugin";
        std::exit(1);
    }

    PluginManager::Manager<Trade::AbstractImporter> importerManager{MAGNUM_PLUGINS_IMPORTER_DIR};
    _importer = importerManager.loadAndInstantiate("PngImporter");
    if(!_importer) {
        Error() << "Cannot load image importer plugin";
        std::exit(1);
    }

    Renderbuffer multisampleColor, multisampleDepth;
    multisampleColor.setStorageMultisample(16, RenderbufferFormat::RGBA8, ImageSize);
    multisampleDepth.setStorageMultisample(16, RenderbufferFormat::DepthComponent24, ImageSize);

    Framebuffer multisampleFramebuffer{{{}, ImageSize}};
    multisampleFramebuffer.attachRenderbuffer(Framebuffer::ColorAttachment{0}, multisampleColor)
        .attachRenderbuffer(Framebuffer::BufferAttachment::Depth, multisampleDepth)
        .bind();
    CORRADE_INTERNAL_ASSERT(multisampleFramebuffer.checkStatus(FramebufferTarget::Draw) == Framebuffer::Status::Complete);

    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, ImageSize);
    Framebuffer framebuffer{{{}, ImageSize}};
    framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color);

    Renderer::enable(Renderer::Feature::DepthTest);

    for(auto fun: {&ShaderVisualizer::phong,
                   &ShaderVisualizer::meshVisualizer,
                   &ShaderVisualizer::flat,
                   &ShaderVisualizer::vertexColor,
                   &ShaderVisualizer::vector,
                   &ShaderVisualizer::distanceFieldVector}) {
        multisampleFramebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth);

        std::string filename = (this->*fun)();

        AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), FramebufferBlit::Color);
        Image2D result = framebuffer.read(framebuffer.viewport(), {ColorFormat::RGBA, ColorType::UnsignedByte});
        converter->exportToFile(result, Utility::Directory::join("../", "shaders-" + filename));
    }

    _importer.reset();

    return 0;
}

namespace {
    const auto Projection = Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001f, 100.0f);
    const auto Transformation = Matrix4::translation(Vector3::zAxis(-5.0f));
    const auto BaseColor = Color3::fromHSV(216.0_degf, 0.85f, 1.0f);
    const auto OutlineColor = Color3{0.95f};
}

std::string ShaderVisualizer::phong() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh;
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::UVSphere::solid(16, 32), BufferUsage::StaticDraw);

    Shaders::Phong shader;
    shader.setAmbientColor(Color3(0.025f))
        .setDiffuseColor(BaseColor)
        .setShininess(200.0f)
        .setLightPosition({5.0f, 5.0f, 7.0f})
        .setProjectionMatrix(Projection)
        .setTransformationMatrix(Transformation)
        .setNormalMatrix(Transformation.rotationScaling());

    mesh.draw(shader);

    return "phong.png";
}

std::string ShaderVisualizer::meshVisualizer() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh;
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::Icosphere::solid(1), BufferUsage::StaticDraw);

    const Matrix4 projection = Projection*Transformation*
        Matrix4::rotationZ(13.7_degf)*
        Matrix4::rotationX(-12.6_degf);

    Shaders::MeshVisualizer shader{Shaders::MeshVisualizer::Flag::Wireframe};
    shader.setColor(BaseColor)
        .setWireframeColor(OutlineColor)
        .setViewportSize(Vector2{ImageSize})
        .setTransformationProjectionMatrix(projection);

    mesh.draw(shader);

    return "meshvisualizer.png";
}

std::string ShaderVisualizer::flat() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh;
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::UVSphere::solid(16, 32), BufferUsage::StaticDraw);

    Shaders::Flat3D shader;
    shader.setColor(BaseColor)
        .setTransformationProjectionMatrix(Projection*Transformation);

    mesh.draw(shader);

    return "flat.png";
}

std::string ShaderVisualizer::vertexColor() {
    Trade::MeshData3D sphere = Primitives::UVSphere::solid(32, 64);

    /* Color vertices nearest to given position */
    auto target = Vector3{2.0f, 2.0f, 7.0f}.normalized();
    std::vector<Color3> colors;
    colors.reserve(sphere.positions(0).size());
    for(Vector3 position: sphere.positions(0))
        colors.push_back(Color3::fromHSV(Math::lerp(240.0_degf, 420.0_degf, Math::max(1.0f - (position - target).length(), 0.0f)), 0.85f, 0.85f));

    Buffer vertices, indices;
    vertices.setData(MeshTools::interleave(sphere.positions(0), colors), BufferUsage::StaticDraw);
    indices.setData(sphere.indices(), BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(sphere.indices().size())
        .addVertexBuffer(vertices, 0, Shaders::VertexColor3D::Position{}, Shaders::VertexColor3D::Color{})
        .setIndexBuffer(indices, 0, Mesh::IndexType::UnsignedInt);

    Shaders::VertexColor3D shader;
    shader.setTransformationProjectionMatrix(Projection*Transformation);

    mesh.draw(shader);

    return "vertexcolor.png";
}

std::string ShaderVisualizer::vector() {
    std::optional<Trade::ImageData2D> image;
    if(!_importer->openFile("vector.png") || !(image = _importer->image2D(0))) {
        Error() << "Cannot open vector.png";
        return "vector.png";
    }

    Texture2D texture;
    texture.setMinificationFilter(Sampler::Filter::Linear)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setWrapping(Sampler::Wrapping::ClampToEdge)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    Mesh mesh;
    std::unique_ptr<Buffer> vertices;
    std::tie(mesh, vertices, std::ignore) = MeshTools::compile(Primitives::Square::solid(Primitives::Square::TextureCoords::Generate), BufferUsage::StaticDraw);

    Shaders::Vector2D shader;
    shader.setColor(BaseColor)
        .setVectorTexture(texture)
        .setTransformationProjectionMatrix({});

    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::One, Renderer::BlendFunction::OneMinusSourceAlpha);
    Renderer::setBlendEquation(Renderer::BlendEquation::Add, Renderer::BlendEquation::Add);

    mesh.draw(shader);

    Renderer::disable(Renderer::Feature::Blending);

    return "vector.png";
}

std::string ShaderVisualizer::distanceFieldVector() {
    std::optional<Trade::ImageData2D> image;
    if(!_importer->openFile("vector-distancefield.png") || !(image = _importer->image2D(0))) {
        Error() << "Cannot open vector-distancefield.png";
        return "distancefieldvector.png";
    }

    Texture2D texture;
    texture.setMinificationFilter(Sampler::Filter::Linear)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setWrapping(Sampler::Wrapping::ClampToEdge)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    Mesh mesh;
    std::unique_ptr<Buffer> vertices;
    std::tie(mesh, vertices, std::ignore) = MeshTools::compile(Primitives::Square::solid(Primitives::Square::TextureCoords::Generate), BufferUsage::StaticDraw);

    Shaders::DistanceFieldVector2D shader;
    shader.setColor(BaseColor)
        .setOutlineColor(OutlineColor)
        .setOutlineRange(0.6f, 0.4f)
        .setVectorTexture(texture)
        .setTransformationProjectionMatrix({});

    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::One, Renderer::BlendFunction::OneMinusSourceAlpha);
    Renderer::setBlendEquation(Renderer::BlendEquation::Add, Renderer::BlendEquation::Add);

    mesh.draw(shader);

    Renderer::disable(Renderer::Feature::Blending);

    return "distancefieldvector.png";
}

MAGNUM_WINDOWLESSAPPLICATION_MAIN(ShaderVisualizer)
<commit_msg>doc: make use of NoCreate tag.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014, 2015
              Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>

#ifdef CORRADE_TARGET_APPLE
#include <Magnum/Platform/WindowlessCglApplication.h>
#elif defined(CORRADE_TARGET_UNIX)
#include <Magnum/Platform/WindowlessGlxApplication.h>
#elif defined(CORRADE_TARGET_WINDOWS)
#include <Magnum/Platform/WindowlessWglApplication.h>
#else
#error no windowless application available on this platform
#endif

#include <Magnum/Buffer.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Image.h>
#include <Magnum/Mesh.h>
#include <Magnum/Renderbuffer.h>
#include <Magnum/RenderbufferFormat.h>
#include <Magnum/MeshTools/Compile.h>
#include <Magnum/MeshTools/Interleave.h>
#include <Magnum/Primitives/Square.h>
#include <Magnum/Primitives/Circle.h>
#include <Magnum/Primitives/Icosphere.h>
#include <Magnum/Primitives/UVSphere.h>
#include <Magnum/Shaders/Flat.h>
#include <Magnum/Shaders/MeshVisualizer.h>
#include <Magnum/Shaders/Phong.h>
#include <Magnum/Shaders/VertexColor.h>
#include <Magnum/Shaders/Vector.h>
#include <Magnum/Shaders/DistanceFieldVector.h>
#include <Magnum/Trade/AbstractImageConverter.h>
#include <Magnum/Trade/ImageData.h>
#include <Magnum/Trade/MeshData2D.h>
#include <Magnum/Trade/MeshData3D.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Renderer.h>
#include <Magnum/ColorFormat.h>
#include <Magnum/Texture.h>
#include <Magnum/TextureFormat.h>

#include "configure.h"

using namespace Magnum;

struct ShaderVisualizer: Platform::WindowlessApplication {
    using Platform::WindowlessApplication::WindowlessApplication;

    int exec() override;

    std::string phong();
    std::string meshVisualizer();
    std::string flat();
    std::string vertexColor();

    std::string vector();
    std::string distanceFieldVector();

    std::unique_ptr<Trade::AbstractImporter> _importer;
};

namespace {
    constexpr const Vector2i ImageSize{256};
}

int ShaderVisualizer::exec() {
    PluginManager::Manager<Trade::AbstractImageConverter> converterManager{MAGNUM_PLUGINS_IMAGECONVERTER_DIR};
    std::unique_ptr<Trade::AbstractImageConverter> converter = converterManager.loadAndInstantiate("PngImageConverter");
    if(!converter) {
        Error() << "Cannot load image converter plugin";
        std::exit(1);
    }

    PluginManager::Manager<Trade::AbstractImporter> importerManager{MAGNUM_PLUGINS_IMPORTER_DIR};
    _importer = importerManager.loadAndInstantiate("PngImporter");
    if(!_importer) {
        Error() << "Cannot load image importer plugin";
        std::exit(1);
    }

    Renderbuffer multisampleColor, multisampleDepth;
    multisampleColor.setStorageMultisample(16, RenderbufferFormat::RGBA8, ImageSize);
    multisampleDepth.setStorageMultisample(16, RenderbufferFormat::DepthComponent24, ImageSize);

    Framebuffer multisampleFramebuffer{{{}, ImageSize}};
    multisampleFramebuffer.attachRenderbuffer(Framebuffer::ColorAttachment{0}, multisampleColor)
        .attachRenderbuffer(Framebuffer::BufferAttachment::Depth, multisampleDepth)
        .bind();
    CORRADE_INTERNAL_ASSERT(multisampleFramebuffer.checkStatus(FramebufferTarget::Draw) == Framebuffer::Status::Complete);

    Renderbuffer color;
    color.setStorage(RenderbufferFormat::RGBA8, ImageSize);
    Framebuffer framebuffer{{{}, ImageSize}};
    framebuffer.attachRenderbuffer(Framebuffer::ColorAttachment{0}, color);

    Renderer::enable(Renderer::Feature::DepthTest);

    for(auto fun: {&ShaderVisualizer::phong,
                   &ShaderVisualizer::meshVisualizer,
                   &ShaderVisualizer::flat,
                   &ShaderVisualizer::vertexColor,
                   &ShaderVisualizer::vector,
                   &ShaderVisualizer::distanceFieldVector}) {
        multisampleFramebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth);

        std::string filename = (this->*fun)();

        AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), FramebufferBlit::Color);
        Image2D result = framebuffer.read(framebuffer.viewport(), {ColorFormat::RGBA, ColorType::UnsignedByte});
        converter->exportToFile(result, Utility::Directory::join("../", "shaders-" + filename));
    }

    _importer.reset();

    return 0;
}

namespace {
    const auto Projection = Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001f, 100.0f);
    const auto Transformation = Matrix4::translation(Vector3::zAxis(-5.0f));
    const auto BaseColor = Color3::fromHSV(216.0_degf, 0.85f, 1.0f);
    const auto OutlineColor = Color3{0.95f};
}

std::string ShaderVisualizer::phong() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh{NoCreate};
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::UVSphere::solid(16, 32), BufferUsage::StaticDraw);

    Shaders::Phong shader;
    shader.setAmbientColor(Color3(0.025f))
        .setDiffuseColor(BaseColor)
        .setShininess(200.0f)
        .setLightPosition({5.0f, 5.0f, 7.0f})
        .setProjectionMatrix(Projection)
        .setTransformationMatrix(Transformation)
        .setNormalMatrix(Transformation.rotationScaling());

    mesh.draw(shader);

    return "phong.png";
}

std::string ShaderVisualizer::meshVisualizer() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh{NoCreate};
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::Icosphere::solid(1), BufferUsage::StaticDraw);

    const Matrix4 projection = Projection*Transformation*
        Matrix4::rotationZ(13.7_degf)*
        Matrix4::rotationX(-12.6_degf);

    Shaders::MeshVisualizer shader{Shaders::MeshVisualizer::Flag::Wireframe};
    shader.setColor(BaseColor)
        .setWireframeColor(OutlineColor)
        .setViewportSize(Vector2{ImageSize})
        .setTransformationProjectionMatrix(projection);

    mesh.draw(shader);

    return "meshvisualizer.png";
}

std::string ShaderVisualizer::flat() {
    std::unique_ptr<Buffer> vertices, indices;
    Mesh mesh{NoCreate};
    std::tie(mesh, vertices, indices) = MeshTools::compile(Primitives::UVSphere::solid(16, 32), BufferUsage::StaticDraw);

    Shaders::Flat3D shader;
    shader.setColor(BaseColor)
        .setTransformationProjectionMatrix(Projection*Transformation);

    mesh.draw(shader);

    return "flat.png";
}

std::string ShaderVisualizer::vertexColor() {
    Trade::MeshData3D sphere = Primitives::UVSphere::solid(32, 64);

    /* Color vertices nearest to given position */
    auto target = Vector3{2.0f, 2.0f, 7.0f}.normalized();
    std::vector<Color3> colors;
    colors.reserve(sphere.positions(0).size());
    for(Vector3 position: sphere.positions(0))
        colors.push_back(Color3::fromHSV(Math::lerp(240.0_degf, 420.0_degf, Math::max(1.0f - (position - target).length(), 0.0f)), 0.85f, 0.85f));

    Buffer vertices, indices;
    vertices.setData(MeshTools::interleave(sphere.positions(0), colors), BufferUsage::StaticDraw);
    indices.setData(sphere.indices(), BufferUsage::StaticDraw);

    Mesh mesh;
    mesh.setPrimitive(MeshPrimitive::Triangles)
        .setCount(sphere.indices().size())
        .addVertexBuffer(vertices, 0, Shaders::VertexColor3D::Position{}, Shaders::VertexColor3D::Color{})
        .setIndexBuffer(indices, 0, Mesh::IndexType::UnsignedInt);

    Shaders::VertexColor3D shader;
    shader.setTransformationProjectionMatrix(Projection*Transformation);

    mesh.draw(shader);

    return "vertexcolor.png";
}

std::string ShaderVisualizer::vector() {
    std::optional<Trade::ImageData2D> image;
    if(!_importer->openFile("vector.png") || !(image = _importer->image2D(0))) {
        Error() << "Cannot open vector.png";
        return "vector.png";
    }

    Texture2D texture;
    texture.setMinificationFilter(Sampler::Filter::Linear)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setWrapping(Sampler::Wrapping::ClampToEdge)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    Mesh mesh{NoCreate};
    std::unique_ptr<Buffer> vertices;
    std::tie(mesh, vertices, std::ignore) = MeshTools::compile(Primitives::Square::solid(Primitives::Square::TextureCoords::Generate), BufferUsage::StaticDraw);

    Shaders::Vector2D shader;
    shader.setColor(BaseColor)
        .setVectorTexture(texture)
        .setTransformationProjectionMatrix({});

    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::One, Renderer::BlendFunction::OneMinusSourceAlpha);
    Renderer::setBlendEquation(Renderer::BlendEquation::Add, Renderer::BlendEquation::Add);

    mesh.draw(shader);

    Renderer::disable(Renderer::Feature::Blending);

    return "vector.png";
}

std::string ShaderVisualizer::distanceFieldVector() {
    std::optional<Trade::ImageData2D> image;
    if(!_importer->openFile("vector-distancefield.png") || !(image = _importer->image2D(0))) {
        Error() << "Cannot open vector-distancefield.png";
        return "distancefieldvector.png";
    }

    Texture2D texture;
    texture.setMinificationFilter(Sampler::Filter::Linear)
        .setMagnificationFilter(Sampler::Filter::Linear)
        .setWrapping(Sampler::Wrapping::ClampToEdge)
        .setStorage(1, TextureFormat::RGBA8, image->size())
        .setSubImage(0, {}, *image);

    Mesh mesh{NoCreate};
    std::unique_ptr<Buffer> vertices;
    std::tie(mesh, vertices, std::ignore) = MeshTools::compile(Primitives::Square::solid(Primitives::Square::TextureCoords::Generate), BufferUsage::StaticDraw);

    Shaders::DistanceFieldVector2D shader;
    shader.setColor(BaseColor)
        .setOutlineColor(OutlineColor)
        .setOutlineRange(0.6f, 0.4f)
        .setVectorTexture(texture)
        .setTransformationProjectionMatrix({});

    Renderer::enable(Renderer::Feature::Blending);
    Renderer::setBlendFunction(Renderer::BlendFunction::One, Renderer::BlendFunction::OneMinusSourceAlpha);
    Renderer::setBlendEquation(Renderer::BlendEquation::Add, Renderer::BlendEquation::Add);

    mesh.draw(shader);

    Renderer::disable(Renderer::Feature::Blending);

    return "distancefieldvector.png";
}

MAGNUM_WINDOWLESSAPPLICATION_MAIN(ShaderVisualizer)
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_LB_CLUSTER_HXX
#define BENG_LB_CLUSTER_HXX

#include "StickyHash.hxx"
#include "avahi/ExplorerListener.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "net/FailureRef.hxx"
#include "io/Logger.hxx"
#include "util/LeakDetector.hxx"

#include <boost/intrusive/set.hpp>

#include <forward_list>
#include <vector>
#include <string>
#include <memory>

struct LbConfig;
struct LbGotoIfConfig;
struct LbListenerConfig;
struct LbClusterConfig;
class LbMonitorStock;
class LbMonitorRef;
class FailureManager;
class MyAvahiClient;
class StickyCache;
class AvahiServiceExplorer;

class LbCluster final : AvahiServiceExplorerListener {
    const LbClusterConfig &config;
    FailureManager &failure_manager;
    LbMonitorStock *const monitors;

    const Logger logger;

    std::unique_ptr<AvahiServiceExplorer> explorer;

    class StickyRing;
    StickyRing *sticky_ring = nullptr;

    StickyCache *sticky_cache = nullptr;

    /**
     * A list of #LbMonitorRef instances, one for each static member
     * (i.e. not Zeroconf).
     */
    std::forward_list<LbMonitorRef> static_member_monitors;

    class Member
        : LeakDetector,
          public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

        const std::string key;

        AllocatedSocketAddress address;

        FailureRef failure;

        std::unique_ptr<LbMonitorRef> monitor;

        mutable std::string log_name;

        unsigned refs = 1;

    public:
        Member(const std::string &_key, SocketAddress _address,
               ReferencedFailureInfo &_failure,
               LbMonitorStock *monitors);
        ~Member();

        Member(const Member &) = delete;
        Member &operator=(const Member &) = delete;

        void Ref() noexcept {
            ++refs;
        }

        void Unref() noexcept {
            if (--refs == 0)
                delete this;
        }

        const std::string &GetKey() const {
            return key;
        }

        SocketAddress GetAddress() const {
            return address;
        }

        void SetAddress(SocketAddress _address) {
            address = _address;
        }

        auto &GetFailureRef() noexcept {
            return failure;
        }

        FailureInfo &GetFailureInfo() {
            return *failure;
        }

        /**
         * Obtain a name identifying this object for logging.
         */
        gcc_pure
        const char *GetLogName() const noexcept;

        struct Compare {
            bool operator()(const Member &a, const Member &b) const {
                return a.key < b.key;
            }

            bool operator()(const Member &a, const std::string &b) const {
                return a.key < b;
            }

            bool operator()(const std::string &a, const Member &b) const {
                return a < b.key;
            }
        };

        struct UnrefDisposer {
            void operator()(Member *member) const noexcept {
                member->Unref();
            }
        };
    };

public:
    /**
     * A (counted) reference to a #Member.  It keeps the #Member valid
     * even if it gets removed because the Zeroconf entry disappears.
     */
    class MemberPtr {
        Member *value = nullptr;

    public:
        MemberPtr() = default;

        MemberPtr(Member *_value) noexcept
            :value(_value) {
            if (value != nullptr)
                value->Ref();
        }

        MemberPtr(Member &_value) noexcept
            :value(&_value) {
            value->Ref();
        }

        MemberPtr(const MemberPtr &src) noexcept
            :MemberPtr(src.value) {}

        MemberPtr(MemberPtr &&src) noexcept
            :value(std::exchange(src.value, nullptr)) {}

        ~MemberPtr() {
            if (value != nullptr)
                value->Unref();
        }

        MemberPtr &operator=(const MemberPtr &src) noexcept {
            if (value != src.value) {
                if (value != nullptr)
                    value->Unref();

                value = src.value;

                if (value != nullptr)
                    value->Ref();
            }

            return *this;
        }

        MemberPtr &operator=(MemberPtr &&src) noexcept {
            std::swap(value, src.value);
            return *this;
        }

        Member *operator->() {
            return value;
        }

        Member &operator*() {
            return *value;
        }

        operator bool() const {
            return value != nullptr;
        }
    };

private:
    typedef boost::intrusive::set<Member,
                                  boost::intrusive::compare<Member::Compare>,
                                  boost::intrusive::constant_time_size<false>> MemberMap;
    MemberMap members;

    std::vector<MemberMap::pointer> active_members;

    bool dirty = false;

    unsigned last_pick = 0;

public:
    LbCluster(const LbClusterConfig &_config, FailureManager &_failure_manager,
              LbMonitorStock *_monitors,
              MyAvahiClient &avahi_client);
    ~LbCluster();

    const LbClusterConfig &GetConfig() const {
        return config;
    }

    gcc_pure
    size_t GetZeroconfCount() {
        if (dirty) {
            dirty = false;
            FillActive();
        }

        return active_members.size();
    }

    Member *Pick(Expiry now, sticky_hash_t sticky_hash);

private:
    void FillActive();

    /**
     * Pick the next active Zeroconf member in a round-robin way.
     * Does not update the #StickyCache.
     */
    MemberMap::reference PickNextZeroconf();

    /**
     * Like PickNextZeroconf(), but skips members which are bad
     * according to failure_get_status().  If all are bad, a random
     * (bad) one is returned.
     */
    MemberMap::reference PickNextGoodZeroconf(Expiry now);

    /* virtual methods from class AvahiServiceExplorerListener */
    void OnAvahiNewObject(const std::string &key,
                          SocketAddress address) noexcept override;
    void OnAvahiRemoveObject(const std::string &key) noexcept override;
};

#endif
<commit_msg>lb/Cluster: add more API docs<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BENG_LB_CLUSTER_HXX
#define BENG_LB_CLUSTER_HXX

#include "StickyHash.hxx"
#include "avahi/ExplorerListener.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "net/FailureRef.hxx"
#include "io/Logger.hxx"
#include "util/LeakDetector.hxx"

#include <boost/intrusive/set.hpp>

#include <forward_list>
#include <vector>
#include <string>
#include <memory>

struct LbConfig;
struct LbGotoIfConfig;
struct LbListenerConfig;
struct LbClusterConfig;
class LbMonitorStock;
class LbMonitorRef;
class FailureManager;
class MyAvahiClient;
class StickyCache;
class AvahiServiceExplorer;

class LbCluster final : AvahiServiceExplorerListener {
    const LbClusterConfig &config;
    FailureManager &failure_manager;
    LbMonitorStock *const monitors;

    const Logger logger;

    /**
     * This #AvahiServiceExplorer locates Zeroconf nodes.
     */
    std::unique_ptr<AvahiServiceExplorer> explorer;

    class StickyRing;

    /**
     * For consistent hashing.  It is populated by FillActive().
     */
    StickyRing *sticky_ring = nullptr;

    /**
     * @see LbClusterConfig::sticky_cache
     */
    StickyCache *sticky_cache = nullptr;

    /**
     * A list of #LbMonitorRef instances, one for each static member
     * (i.e. not Zeroconf).
     */
    std::forward_list<LbMonitorRef> static_member_monitors;

    class Member
        : LeakDetector,
          public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

        const std::string key;

        AllocatedSocketAddress address;

        FailureRef failure;

        std::unique_ptr<LbMonitorRef> monitor;

        mutable std::string log_name;

        unsigned refs = 1;

    public:
        Member(const std::string &_key, SocketAddress _address,
               ReferencedFailureInfo &_failure,
               LbMonitorStock *monitors);
        ~Member();

        Member(const Member &) = delete;
        Member &operator=(const Member &) = delete;

        void Ref() noexcept {
            ++refs;
        }

        void Unref() noexcept {
            if (--refs == 0)
                delete this;
        }

        const std::string &GetKey() const {
            return key;
        }

        SocketAddress GetAddress() const {
            return address;
        }

        void SetAddress(SocketAddress _address) {
            address = _address;
        }

        auto &GetFailureRef() noexcept {
            return failure;
        }

        FailureInfo &GetFailureInfo() {
            return *failure;
        }

        /**
         * Obtain a name identifying this object for logging.
         */
        gcc_pure
        const char *GetLogName() const noexcept;

        struct Compare {
            bool operator()(const Member &a, const Member &b) const {
                return a.key < b.key;
            }

            bool operator()(const Member &a, const std::string &b) const {
                return a.key < b;
            }

            bool operator()(const std::string &a, const Member &b) const {
                return a < b.key;
            }
        };

        struct UnrefDisposer {
            void operator()(Member *member) const noexcept {
                member->Unref();
            }
        };
    };

public:
    /**
     * A (counted) reference to a #Member.  It keeps the #Member valid
     * even if it gets removed because the Zeroconf entry disappears.
     */
    class MemberPtr {
        Member *value = nullptr;

    public:
        MemberPtr() = default;

        MemberPtr(Member *_value) noexcept
            :value(_value) {
            if (value != nullptr)
                value->Ref();
        }

        MemberPtr(Member &_value) noexcept
            :value(&_value) {
            value->Ref();
        }

        MemberPtr(const MemberPtr &src) noexcept
            :MemberPtr(src.value) {}

        MemberPtr(MemberPtr &&src) noexcept
            :value(std::exchange(src.value, nullptr)) {}

        ~MemberPtr() {
            if (value != nullptr)
                value->Unref();
        }

        MemberPtr &operator=(const MemberPtr &src) noexcept {
            if (value != src.value) {
                if (value != nullptr)
                    value->Unref();

                value = src.value;

                if (value != nullptr)
                    value->Ref();
            }

            return *this;
        }

        MemberPtr &operator=(MemberPtr &&src) noexcept {
            std::swap(value, src.value);
            return *this;
        }

        Member *operator->() {
            return value;
        }

        Member &operator*() {
            return *value;
        }

        operator bool() const {
            return value != nullptr;
        }
    };

private:
    typedef boost::intrusive::set<Member,
                                  boost::intrusive::compare<Member::Compare>,
                                  boost::intrusive::constant_time_size<false>> MemberMap;

    /**
     * All Zeroconf members.  Managed by our
     * AvahiServiceExplorerListener virtual method overrides.
     */
    MemberMap members;

    /**
     * All #members pointers as a std::vector.  Populated by
     * FillActive().
     */
    std::vector<MemberMap::pointer> active_members;

    bool dirty = false;

    unsigned last_pick = 0;

public:
    LbCluster(const LbClusterConfig &_config, FailureManager &_failure_manager,
              LbMonitorStock *_monitors,
              MyAvahiClient &avahi_client);
    ~LbCluster();

    const LbClusterConfig &GetConfig() const {
        return config;
    }

    gcc_pure
    size_t GetZeroconfCount() {
        if (dirty) {
            dirty = false;
            FillActive();
        }

        return active_members.size();
    }

    /**
     * Pick a member for the next request.
     *
     * Zeroconf only.
     */
    Member *Pick(Expiry now, sticky_hash_t sticky_hash);

private:
    /**
     * Fill #active_members and #sticky_ring.
     *
     * Zeroconf only.
     */
    void FillActive();

    /**
     * Pick the next active Zeroconf member in a round-robin way.
     * Does not update the #StickyCache.
     */
    MemberMap::reference PickNextZeroconf();

    /**
     * Like PickNextZeroconf(), but skips members which are bad
     * according to failure_get_status().  If all are bad, a random
     * (bad) one is returned.
     */
    MemberMap::reference PickNextGoodZeroconf(Expiry now);

    /* virtual methods from class AvahiServiceExplorerListener */
    void OnAvahiNewObject(const std::string &key,
                          SocketAddress address) noexcept override;
    void OnAvahiRemoveObject(const std::string &key) noexcept override;
};

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///\file Contains the Range template class (aka span or array_view).

#pragma once

#ifndef NYTL_INCLUDE_RANGE_HPP
#define NYTL_INCLUDE_RANGE_HPP

#include <cstdlib>
#include <stdexcept>

namespace nytl
{

namespace detail { template<typename T, typename C, typename = void> struct ValidContainer; }

///The Range class represents a part of a non-owned contiguous sequence.
///Can be useful to pass mulitple parameters (without size limitations) to a function.
///Does not allocate any additional memory on the heap since it simply references the
///sequence it was constructed with. Therefore one must assure that the sequence will live longer
///than the Range object.
///It can be implicitly constructed (converted) from containers that have a "data" and a
///"size" member function, e.g. std::vector, std::string and std::string.
///Note that one cannot construct a Range from non-contiguous containers such as list,
///deque or map.
///Alternative names: span, array_view
template<typename T>
class Range
{
public:
	using Value = std::remove_const_t<T>;
	using Pointer = Value*;
	using ConstPointer = const Value*;
	using Reference = Value&;
	using ConstReference = const Value&;
	using Size = std::size_t;
	using Iterator = ConstPointer;
	using ConstIterator = ConstPointer;
	using ReverseIterator = std::reverse_iterator<Iterator>;
	using ConstReverseIterator = std::reverse_iterator<ConstIterator>;

	using value_type = Value;
	using pointer = Pointer;
	using const_pointer = ConstPointer;
	using reference = Reference;
	using const_reference = ConstReference;
	using iterator = Iterator;
	using const_iterator = ConstIterator;
	using reverse_iterator = ReverseIterator;
	using const_reverse_iterator = ConstReverseIterator;
	using size_type = Size;
	using difference_type = std::ptrdiff_t;

public:
	constexpr Range() noexcept = default;
	constexpr Range(std::nullptr_t, std::size_t = 0) noexcept : data_(nullptr), size_(0) {}
	constexpr Range(const T& value, std::size_t size) noexcept : data_(&value), size_(size) {}
	constexpr Range(const T* value, std::size_t size) noexcept : data_(value), size_(size) {}
	constexpr Range(std::initializer_list<T> l) noexcept : data_(l.begin()), size_(l.size()) {}

	template<std::size_t N> constexpr Range(const T (&arr)[N]) noexcept : data_(arr), size_(N) {}

	template<typename C, typename = typename detail::ValidContainer<T, C>::type>
	Range(const C& con) noexcept : data_(con.size()), size_(con.size()) {}

	constexpr ConstPointer data() const noexcept { return data_; }
	constexpr std::size_t size() const noexcept { return size_; }
	constexpr bool empty() const noexcept { return size() == 0; }
	constexpr Size max_size() const noexcept { return size(); }

	constexpr Iterator begin() const noexcept { return data_; }
	constexpr Iterator end() const noexcept { return data_ + size_; }

	constexpr ConstIterator cbegin() const noexcept { return data_; }
	constexpr ConstIterator cend() const noexcept { return data_ + size_; }

	constexpr ReverseIterator rbegin() const noexcept { return {end()}; }
	constexpr ReverseIterator rend() const noexcept { return {begin()}; }

	constexpr ConstReverseIterator crbegin() const noexcept { return {cend()}; }
	constexpr ConstReverseIterator crend() const noexcept { return {cbegin()}; }

	constexpr ConstReference operator[](Size i) const noexcept { return *(data_ + i); }
	constexpr ConstReference at(Size i) const
		{ if(i >= size_) throw std::out_of_range("Range::at"); return data_[i]; }

	constexpr ConstReference front() const noexcept { return *data_; }
	constexpr ConstReference back() const noexcept { return *(data_ + size_); }

	constexpr Range<T> slice(Size pos, Size size) const noexcept { return {data_ + pos, size}; }

	///\{
	///Those function can be used to copy the range to an owned container.
	///range.as<std::vector>() will convert into an vector of the range type (T).
	///range.as<std::vector<float>>() will convert into an float-vector (if possible).
	template<typename C> C as() const { return C(data_, data_ + size_); }
	template<template<class...> class C> C<T> as() const { return C<T>(data_, data_ + size_); }
	///\}

protected:
	ConstPointer data_ = nullptr;
	Size size_ = 0;
};

namespace detail
{

template<typename T, typename C>
struct ValidContainer<T, C,
	typename std::enable_if<
		std::is_convertible<
			decltype(*std::declval<C>().data()),
			const T&
		>::value &&
		std::is_convertible<
			decltype(std::declval<C>().size()),
			std::size_t
		>::value
	>::type
> { using type = void; };

}

}

#endif //header guard
<commit_msg>range fix<commit_after>// Copyright (c) 2016 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///\file Contains the Range template class (aka span or array_view).

#pragma once

#ifndef NYTL_INCLUDE_RANGE_HPP
#define NYTL_INCLUDE_RANGE_HPP

#include <cstdlib>
#include <stdexcept>

namespace nytl
{

namespace detail { template<typename T, typename C, typename = void> struct ValidContainer; }

///The Range class represents a part of a non-owned contiguous sequence.
///Can be useful to pass mulitple parameters (without size limitations) to a function.
///Does not allocate any additional memory on the heap since it simply references the
///sequence it was constructed with. Therefore one must assure that the sequence will live longer
///than the Range object.
///It can be implicitly constructed (converted) from containers that have a "data" and a
///"size" member function, e.g. std::vector, std::string and std::string.
///Note that one cannot construct a Range from non-contiguous containers such as list,
///deque or map.
///Alternative names: span, array_view
template<typename T>
class Range
{
public:
	using Value = std::remove_const_t<T>;
	using Pointer = Value*;
	using ConstPointer = const Value*;
	using Reference = Value&;
	using ConstReference = const Value&;
	using Size = std::size_t;
	using Iterator = ConstPointer;
	using ConstIterator = ConstPointer;
	using ReverseIterator = std::reverse_iterator<Iterator>;
	using ConstReverseIterator = std::reverse_iterator<ConstIterator>;

	using value_type = Value;
	using pointer = Pointer;
	using const_pointer = ConstPointer;
	using reference = Reference;
	using const_reference = ConstReference;
	using iterator = Iterator;
	using const_iterator = ConstIterator;
	using reverse_iterator = ReverseIterator;
	using const_reverse_iterator = ConstReverseIterator;
	using size_type = Size;
	using difference_type = std::ptrdiff_t;

public:
	constexpr Range() noexcept = default;
	constexpr Range(std::nullptr_t, std::size_t = 0) noexcept : data_(nullptr), size_(0) {}
	constexpr Range(const T& value, std::size_t size) noexcept : data_(&value), size_(size) {}
	constexpr Range(const T* value, std::size_t size) noexcept : data_(value), size_(size) {}
	constexpr Range(std::initializer_list<T> l) noexcept : data_(l.begin()), size_(l.size()) {}

	template<std::size_t N> constexpr Range(const T (&arr)[N]) noexcept : data_(arr), size_(N) {}

	template<typename C, typename = typename detail::ValidContainer<T, C>::type>
	Range(const C& con) noexcept : data_(con.data()), size_(con.size()) {}

	constexpr ConstPointer data() const noexcept { return data_; }
	constexpr std::size_t size() const noexcept { return size_; }
	constexpr bool empty() const noexcept { return size() == 0; }
	constexpr Size max_size() const noexcept { return size(); }

	constexpr Iterator begin() const noexcept { return data_; }
	constexpr Iterator end() const noexcept { return data_ + size_; }

	constexpr ConstIterator cbegin() const noexcept { return data_; }
	constexpr ConstIterator cend() const noexcept { return data_ + size_; }

	constexpr ReverseIterator rbegin() const noexcept { return {end()}; }
	constexpr ReverseIterator rend() const noexcept { return {begin()}; }

	constexpr ConstReverseIterator crbegin() const noexcept { return {cend()}; }
	constexpr ConstReverseIterator crend() const noexcept { return {cbegin()}; }

	constexpr ConstReference operator[](Size i) const noexcept { return *(data_ + i); }
	constexpr ConstReference at(Size i) const
		{ if(i >= size_) throw std::out_of_range("Range::at"); return data_[i]; }

	constexpr ConstReference front() const noexcept { return *data_; }
	constexpr ConstReference back() const noexcept { return *(data_ + size_); }

	constexpr Range<T> slice(Size pos, Size size) const noexcept { return {data_ + pos, size}; }

	///\{
	///Those function can be used to copy the range to an owned container.
	///range.as<std::vector>() will convert into an vector of the range type (T).
	///range.as<std::vector<float>>() will convert into an float-vector (if possible).
	template<typename C> C as() const { return C(data_, data_ + size_); }
	template<template<class...> class C> C<T> as() const { return C<T>(data_, data_ + size_); }
	///\}

protected:
	ConstPointer data_ = nullptr;
	Size size_ = 0;
};

namespace detail
{

template<typename T, typename C>
struct ValidContainer<T, C,
	typename std::enable_if<
		std::is_convertible<
			decltype(*std::declval<C>().data()),
			const T&
		>::value &&
		std::is_convertible<
			decltype(std::declval<C>().size()),
			std::size_t
		>::value
	>::type
> { using type = void; };

}

}

#endif //header guard
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    QVTKGraphicsItem.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2010 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "QVTKGraphicsItem.h"
#include <QGLFramebufferObject>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>

#include "QVTKInteractor.h"
#include "vtkGenericOpenGLRenderWindow.h"
#include "vtkEventQtSlotConnect.h"
#include "vtkgl.h"

QVTKGraphicsItem::QVTKGraphicsItem(QGLContext* ctx, QGraphicsItem* p)
  : QGraphicsWidget(p), mContext(ctx)
{
  mFBO = NULL;
  mIren = vtkSmartPointer<QVTKInteractor>::New();
  mIrenAdapter = new QVTKInteractorAdapter(this);
  mConnect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
  mConnect->Connect(mIren, vtkCommand::RenderEvent, this, SLOT(Update()));
  vtkSmartPointer<vtkGenericOpenGLRenderWindow> win = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  this->SetRenderWindow(win);

  this->setFlag(QGraphicsItem::ItemIsFocusable, true);
  setFocusPolicy(Qt::ClickFocus);
  setAcceptHoverEvents(true);
  this->setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding));
}

QVTKGraphicsItem::~QVTKGraphicsItem()
{
  if(mFBO)
    delete mFBO;
}

void QVTKGraphicsItem::SetRenderWindow(vtkGenericOpenGLRenderWindow* win)
{
  if(mWin)
  {
    mConnect->Disconnect(mWin, vtkCommand::StartEvent, this, SLOT(Start()));
    mConnect->Disconnect(mWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent()));
    mConnect->Disconnect(mWin, vtkCommand::EndEvent, this, SLOT(End()));
    mConnect->Disconnect(mWin, vtkCommand::WindowFrameEvent, this, SLOT(Update()));
    mConnect->Disconnect(mWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*)));
  }

  mIren->SetRenderWindow(win);
  mWin = win;

  if(mWin)
  {
    mWin->SetDoubleBuffer(0);
    mWin->SetFrontBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetFrontLeftBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetBackBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetBackLeftBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);

    mConnect->Connect(mWin, vtkCommand::StartEvent, this, SLOT(Start()));
    mConnect->Connect(mWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent()));
    mConnect->Connect(mWin, vtkCommand::EndEvent, this, SLOT(End()));
    mConnect->Connect(mWin, vtkCommand::WindowFrameEvent, this, SLOT(Update()));
    mConnect->Connect(mWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*)));
  }
}

vtkGenericOpenGLRenderWindow* QVTKGraphicsItem::GetRenderWindow() const
{
  return mWin;
}

QVTKInteractor* QVTKGraphicsItem::GetInteractor() const
{
  return mIren;
}

void QVTKGraphicsItem::Update()
{
  this->update(boundingRect());
};

void QVTKGraphicsItem::MakeCurrent()
{
  mContext->makeCurrent();

  QSize sz = this->size().toSize();
  if(!mFBO || sz != mFBO->size())
  {
    if(mFBO)
      delete mFBO;

    if(!sz.isEmpty())
      mFBO = new QGLFramebufferObject(sz, QGLFramebufferObject::Depth);
  }

  if(mFBO)
    mFBO->bind();
}

void QVTKGraphicsItem::Start()
{
  MakeCurrent();

  if(!mFBO)
  {
    mWin->SetAbortRender(1);
    return;
  }

  glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
  glPushAttrib(GL_ALL_ATTRIB_BITS);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();

  mWin->OpenGLInit();
}

void QVTKGraphicsItem::End()
{
  if(!mFBO)
    return;

  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

  glPopClientAttrib();
  glPopAttrib();

  mFBO->release();
}

void QVTKGraphicsItem::IsCurrent(vtkObject*, unsigned long, void*, void* call_data)
{
  if(mFBO)
  {
    bool* ptr = reinterpret_cast<bool*>(call_data);
    *ptr = QGLContext::currentContext() == mContext && mFBO->isBound();
  }
}

#if QT_VERSION >= 0x040600
void QVTKGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
#else
void QVTKGraphicsItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
#endif
{
  if(!mWin)
    return;

#if QT_VERSION >= 0x040600
  // tell Qt we're doing our own GL calls
  // if necessary, it'll put us in an OpenGL 1.x compatible state.
  painter->beginNativePainting();
#endif

  if(!mFBO || this->size().toSize() != mFBO->size())
  {
    // first time or is enabled
    // if its not the first time and it is disabled, don't update the scene
    if(!mFBO || isEnabled())
    {
      mIren->Render();
    }
  }

  if(!mFBO)
    return;

  // simply draw the already existing texture to the scene
  // modifications to the texture is done using the VTK api (e.g. vtkRenderWindow::Render())
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, mFBO->texture());

  glDisable(GL_BLEND);

  QRectF r = this->rect();

  glColor4f(1,1,1,1);
  glBegin(GL_QUADS);
  glTexCoord2i(0,1);
  glVertex2f(r.left(),r.top());
  glTexCoord2i(1,1);
  glVertex2f(r.right(),r.top());
  glTexCoord2i(1,0);
  glVertex2f(r.right(),r.bottom());
  glTexCoord2i(0,0);
  glVertex2f(r.left(),r.bottom());
  glEnd();

#if QT_VERSION >= 0x040600
  painter->endNativePainting();
#endif
}

void QVTKGraphicsItem::keyPressEvent(QKeyEvent* e)
{
  e->accept();
  mIrenAdapter->ProcessEvent(e, mIren);
}

void QVTKGraphicsItem::keyReleaseEvent(QKeyEvent* e)
{
  e->accept();
  mIrenAdapter->ProcessEvent(e, mIren);
}

void QVTKGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();

  e->accept();
  QMouseEvent e2(QEvent::MouseButtonPress, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  e->accept();
  QMouseEvent e2(QEvent::MouseButtonRelease, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  e->accept();
  QMouseEvent e2(QEvent::MouseMove, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::wheelEvent(QGraphicsSceneWheelEvent* e)
{
  e->accept();
  QWheelEvent e2(e->pos().toPoint(), e->scenePos().toPoint(), e->delta(),
      e->buttons(), e->modifiers(), e->orientation());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::resizeEvent(QGraphicsSceneResizeEvent* e)
{
  e->accept();
  QResizeEvent e2(e->newSize().toSize(), e->oldSize().toSize());
  mIrenAdapter->ProcessEvent(&e2, mIren);
  if(mWin)
    mWin->SetSize(e->newSize().width(), e->newSize().height());

}

void QVTKGraphicsItem::moveEvent(QGraphicsSceneMoveEvent* e)
{
  e->accept();
  QMoveEvent e2(e->newPos().toPoint(), e->oldPos().toPoint());
  if(mWin)
    mWin->SetPosition(e->newPos().x(), e->newPos().y());
}

void QVTKGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QEvent e2(QEvent::Enter);
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QEvent e2(QEvent::Leave);
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  QMouseEvent e2(QEvent::MouseMove, pi, Qt::NoButton, Qt::NoButton, e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}
<commit_msg>Fix compile warnings<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    QVTKGraphicsItem.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2010 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "QVTKGraphicsItem.h"
#include <QGLFramebufferObject>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>

#include "QVTKInteractor.h"
#include "vtkGenericOpenGLRenderWindow.h"
#include "vtkEventQtSlotConnect.h"
#include "vtkgl.h"

QVTKGraphicsItem::QVTKGraphicsItem(QGLContext* ctx, QGraphicsItem* p)
  : QGraphicsWidget(p), mContext(ctx)
{
  mFBO = NULL;
  mIren = vtkSmartPointer<QVTKInteractor>::New();
  mIrenAdapter = new QVTKInteractorAdapter(this);
  mConnect = vtkSmartPointer<vtkEventQtSlotConnect>::New();
  mConnect->Connect(mIren, vtkCommand::RenderEvent, this, SLOT(Update()));
  vtkSmartPointer<vtkGenericOpenGLRenderWindow> win = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  this->SetRenderWindow(win);

  this->setFlag(QGraphicsItem::ItemIsFocusable, true);
  setFocusPolicy(Qt::ClickFocus);
  setAcceptHoverEvents(true);
  this->setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding));
}

QVTKGraphicsItem::~QVTKGraphicsItem()
{
  if(mFBO)
    delete mFBO;
}

void QVTKGraphicsItem::SetRenderWindow(vtkGenericOpenGLRenderWindow* win)
{
  if(mWin)
  {
    mConnect->Disconnect(mWin, vtkCommand::StartEvent, this, SLOT(Start()));
    mConnect->Disconnect(mWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent()));
    mConnect->Disconnect(mWin, vtkCommand::EndEvent, this, SLOT(End()));
    mConnect->Disconnect(mWin, vtkCommand::WindowFrameEvent, this, SLOT(Update()));
    mConnect->Disconnect(mWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*)));
  }

  mIren->SetRenderWindow(win);
  mWin = win;

  if(mWin)
  {
    mWin->SetDoubleBuffer(0);
    mWin->SetFrontBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetFrontLeftBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetBackBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);
    mWin->SetBackLeftBuffer(vtkgl::COLOR_ATTACHMENT0_EXT);

    mConnect->Connect(mWin, vtkCommand::StartEvent, this, SLOT(Start()));
    mConnect->Connect(mWin, vtkCommand::WindowMakeCurrentEvent, this, SLOT(MakeCurrent()));
    mConnect->Connect(mWin, vtkCommand::EndEvent, this, SLOT(End()));
    mConnect->Connect(mWin, vtkCommand::WindowFrameEvent, this, SLOT(Update()));
    mConnect->Connect(mWin, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*)));
  }
}

vtkGenericOpenGLRenderWindow* QVTKGraphicsItem::GetRenderWindow() const
{
  return mWin;
}

QVTKInteractor* QVTKGraphicsItem::GetInteractor() const
{
  return mIren;
}

void QVTKGraphicsItem::Update()
{
  this->update(boundingRect());
};

void QVTKGraphicsItem::MakeCurrent()
{
  mContext->makeCurrent();

  QSize sz = this->size().toSize();
  if(!mFBO || sz != mFBO->size())
  {
    if(mFBO)
      delete mFBO;

    if(!sz.isEmpty())
      mFBO = new QGLFramebufferObject(sz, QGLFramebufferObject::Depth);
  }

  if(mFBO)
    mFBO->bind();
}

void QVTKGraphicsItem::Start()
{
  MakeCurrent();

  if(!mFBO)
  {
    mWin->SetAbortRender(1);
    return;
  }

  glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
  glPushAttrib(GL_ALL_ATTRIB_BITS);

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();

  mWin->OpenGLInit();
}

void QVTKGraphicsItem::End()
{
  if(!mFBO)
    return;

  glMatrixMode(GL_PROJECTION);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

  glPopClientAttrib();
  glPopAttrib();

  mFBO->release();
}

void QVTKGraphicsItem::IsCurrent(vtkObject*, unsigned long, void*, void* call_data)
{
  if(mFBO)
  {
    bool* ptr = reinterpret_cast<bool*>(call_data);
    *ptr = QGLContext::currentContext() == mContext && mFBO->isBound();
  }
}

#if QT_VERSION >= 0x040600
void QVTKGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
#else
void QVTKGraphicsItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
#endif
{
  if(!mWin)
    return;

#if QT_VERSION >= 0x040600
  // tell Qt we're doing our own GL calls
  // if necessary, it'll put us in an OpenGL 1.x compatible state.
  painter->beginNativePainting();
#endif

  if(!mFBO || this->size().toSize() != mFBO->size())
  {
    // first time or is enabled
    // if its not the first time and it is disabled, don't update the scene
    if(!mFBO || isEnabled())
    {
      mIren->Render();
    }
  }

  if(!mFBO)
    return;

  // simply draw the already existing texture to the scene
  // modifications to the texture is done using the VTK api (e.g. vtkRenderWindow::Render())
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, mFBO->texture());

  glDisable(GL_BLEND);

  QRectF r = this->rect();

  glColor4f(1,1,1,1);
  glBegin(GL_QUADS);
  glTexCoord2i(0,1);
  glVertex2f(r.left(),r.top());
  glTexCoord2i(1,1);
  glVertex2f(r.right(),r.top());
  glTexCoord2i(1,0);
  glVertex2f(r.right(),r.bottom());
  glTexCoord2i(0,0);
  glVertex2f(r.left(),r.bottom());
  glEnd();

#if QT_VERSION >= 0x040600
  painter->endNativePainting();
#endif
}

void QVTKGraphicsItem::keyPressEvent(QKeyEvent* e)
{
  e->accept();
  mIrenAdapter->ProcessEvent(e, mIren);
}

void QVTKGraphicsItem::keyReleaseEvent(QKeyEvent* e)
{
  e->accept();
  mIrenAdapter->ProcessEvent(e, mIren);
}

void QVTKGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();

  e->accept();
  QMouseEvent e2(QEvent::MouseButtonPress, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  e->accept();
  QMouseEvent e2(QEvent::MouseButtonRelease, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
{
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  e->accept();
  QMouseEvent e2(QEvent::MouseMove, pi, e->button(),
      e->buttons(), e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::wheelEvent(QGraphicsSceneWheelEvent* e)
{
  e->accept();
  QWheelEvent e2(e->pos().toPoint(), e->scenePos().toPoint(), e->delta(),
      e->buttons(), e->modifiers(), e->orientation());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::resizeEvent(QGraphicsSceneResizeEvent* e)
{
  e->accept();
  QResizeEvent e2(e->newSize().toSize(), e->oldSize().toSize());
  mIrenAdapter->ProcessEvent(&e2, mIren);
  if(mWin)
    mWin->SetSize(e2.size().width(), e2.size().height());

}

void QVTKGraphicsItem::moveEvent(QGraphicsSceneMoveEvent* e)
{
  e->accept();
  QMoveEvent e2(e->newPos().toPoint(), e->oldPos().toPoint());
  if(mWin)
    mWin->SetPosition(e2.pos().x(), e2.pos().y());
}

void QVTKGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QEvent e2(QEvent::Enter);
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QEvent e2(QEvent::Leave);
  mIrenAdapter->ProcessEvent(&e2, mIren);
}

void QVTKGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent* e)
{
  e->accept();
  QPointF pf = e->pos();
  QPoint pi = pf.toPoint();
  QMouseEvent e2(QEvent::MouseMove, pi, Qt::NoButton, Qt::NoButton, e->modifiers());
  mIrenAdapter->ProcessEvent(&e2, mIren);
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 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/automation/automation_resource_message_filter.h"

#include "base/histogram.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/automation/url_request_automation_job.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/net/url_request_slow_download_job.h"
#include "chrome/browser/net/url_request_slow_http_job.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/test/automation/automation_messages.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_store.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_filter.h"

AutomationResourceMessageFilter::RenderViewMap
    AutomationResourceMessageFilter::filtered_render_views_;

int AutomationResourceMessageFilter::unique_request_id_ = 1;

AutomationResourceMessageFilter::AutomationResourceMessageFilter()
    : channel_(NULL) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          URLRequestAutomationJob::EnsureProtocolFactoryRegistered));
}

AutomationResourceMessageFilter::~AutomationResourceMessageFilter() {
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
  DCHECK(channel_ == NULL);
  channel_ = channel;
}

void AutomationResourceMessageFilter::OnFilterRemoved() {
  channel_ = NULL;
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnChannelClosing() {
  channel_ = NULL;
  request_map_.clear();

  // Only erase RenderViews which are associated with this
  // AutomationResourceMessageFilter instance.
  RenderViewMap::iterator index = filtered_render_views_.begin();
  while (index != filtered_render_views_.end()) {
    const AutomationDetails& details = (*index).second;
    if (details.filter.get() == this) {
      filtered_render_views_.erase(index++);
    } else {
      index++;
    }
  }
}

// Called on the IPC thread:
bool AutomationResourceMessageFilter::OnMessageReceived(
    const IPC::Message& message) {
  int request_id;
  if (URLRequestAutomationJob::MayFilterMessage(message, &request_id)) {
    RequestMap::iterator it = request_map_.find(request_id);
    if (it != request_map_.end()) {
      URLRequestAutomationJob* job = it->second;
      DCHECK(job);
      if (job) {
        job->OnMessage(message);
        return true;
      }
    }
  }

  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(AutomationResourceMessageFilter, message)
    IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet,
                        OnSetFilteredInet)
    IPC_MESSAGE_HANDLER(AutomationMsg_GetFilteredInetHitCount,
                        OnGetFilteredInetHitCount)
    IPC_MESSAGE_HANDLER(AutomationMsg_RecordHistograms,
                        OnRecordHistograms)
    IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesHostResponse,
                        OnGetCookiesHostResponse)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

// Called on the IPC thread:
bool AutomationResourceMessageFilter::Send(IPC::Message* message) {
  // This has to be called on the IO thread.
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  if (!channel_) {
    delete message;
    return false;
  }

  return channel_->Send(message);
}

bool AutomationResourceMessageFilter::RegisterRequest(
    URLRequestAutomationJob* job) {
  if (!job) {
    NOTREACHED();
    return false;
  }
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  // Register pending jobs in the pending request map for servicing later.
  if (job->is_pending()) {
    DCHECK(!ContainsKey(pending_request_map_, job->id()));
    DCHECK(!ContainsKey(request_map_, job->id()));
    pending_request_map_[job->id()] = job;
  } else {
    DCHECK(!ContainsKey(request_map_, job->id()));
    DCHECK(!ContainsKey(pending_request_map_, job->id()));
    request_map_[job->id()] = job;
  }

  return true;
}

void AutomationResourceMessageFilter::UnRegisterRequest(
    URLRequestAutomationJob* job) {
  if (!job) {
    NOTREACHED();
    return;
  }
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (job->is_pending()) {
    DCHECK(ContainsKey(pending_request_map_, job->id()));
    pending_request_map_.erase(job->id());
  } else {
    DCHECK(ContainsKey(request_map_, job->id()));
    request_map_.erase(job->id());
  }
}

bool AutomationResourceMessageFilter::RegisterRenderView(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter,
    bool pending_view) {
  if (!renderer_pid || !renderer_id || !tab_handle) {
    NOTREACHED();
    return false;
  }

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::RegisterRenderViewInIOThread,
          renderer_pid, renderer_id, tab_handle, filter, pending_view));
  return true;
}

void AutomationResourceMessageFilter::UnRegisterRenderView(
    int renderer_pid, int renderer_id) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread,
          renderer_pid, renderer_id));
}

bool AutomationResourceMessageFilter::ResumePendingRenderView(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter) {
  if (!renderer_pid || !renderer_id || !tab_handle) {
    NOTREACHED();
    return false;
  }

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread,
          renderer_pid, renderer_id, tab_handle, filter));
  return true;
}

void AutomationResourceMessageFilter::RegisterRenderViewInIOThread(
    int renderer_pid, int renderer_id,
    int tab_handle, AutomationResourceMessageFilter* filter,
    bool pending_view) {
  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));
  if (automation_details_iter != filtered_render_views_.end()) {
    DCHECK(automation_details_iter->second.ref_count > 0);
    automation_details_iter->second.ref_count++;
  } else {
    filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
        AutomationDetails(tab_handle, filter, pending_view);
  }
}

// static
void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread(
    int renderer_pid, int renderer_id) {
  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));

  if (automation_details_iter == filtered_render_views_.end()) {
    LOG(INFO) << "UnRegisterRenderViewInIOThread: already unregistered";
    return;
  }

  automation_details_iter->second.ref_count--;

  if (automation_details_iter->second.ref_count <= 0) {
    filtered_render_views_.erase(RendererId(renderer_pid, renderer_id));
  }
}

// static
bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));

  if (automation_details_iter == filtered_render_views_.end()) {
    NOTREACHED() << "Failed to find pending view for renderer pid:"
                 << renderer_pid
                 << ", render view id:"
                 << renderer_id;
    return false;
  }

  DCHECK(automation_details_iter->second.is_pending_render_view);

  AutomationResourceMessageFilter* old_filter =
      automation_details_iter->second.filter;
  DCHECK(old_filter != NULL);

  filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
      AutomationDetails(tab_handle, filter, false);

  ResumeJobsForPendingView(tab_handle, old_filter, filter);
  return true;
}

bool AutomationResourceMessageFilter::LookupRegisteredRenderView(
    int renderer_pid, int renderer_id, AutomationDetails* details) {
  bool found = false;
  RenderViewMap::iterator it = filtered_render_views_.find(RendererId(
      renderer_pid, renderer_id));
  if (it != filtered_render_views_.end()) {
    found = true;
    if (details)
      *details = it->second;
  }

  return found;
}

bool AutomationResourceMessageFilter::GetAutomationRequestId(
    int request_id, int* automation_request_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  RequestMap::iterator it = request_map_.begin();
  while (it != request_map_.end()) {
    URLRequestAutomationJob* job = it->second;
    DCHECK(job);
    if (job && job->request_id() == request_id) {
      *automation_request_id = job->id();
      return true;
    }
    it++;
  }

  return false;
}

bool AutomationResourceMessageFilter::SendDownloadRequestToHost(
    int routing_id, int tab_handle, int request_id) {
  int automation_request_id = 0;
  bool valid_id = GetAutomationRequestId(request_id, &automation_request_id);
  if (!valid_id) {
    NOTREACHED() << "Invalid request id: " << request_id;
    return false;
  }

  return Send(new AutomationMsg_DownloadRequestInHost(0, tab_handle,
                                                      automation_request_id));
}

void AutomationResourceMessageFilter::OnSetFilteredInet(bool enable) {
  chrome_browser_net::SetUrlRequestMocksEnabled(enable);
}

void AutomationResourceMessageFilter::OnGetFilteredInetHitCount(
    int* hit_count) {
  *hit_count = URLRequestFilter::GetInstance()->hit_count();
}

void AutomationResourceMessageFilter::OnRecordHistograms(
    const std::vector<std::string>& histogram_list) {
  for (size_t index = 0; index < histogram_list.size(); ++index) {
    Histogram::DeserializeHistogramInfo(histogram_list[index]);
  }
}

void AutomationResourceMessageFilter::GetCookiesForUrl(
    int tab_handle, const GURL& url, net::CompletionCallback* callback,
    net::CookieStore* cookie_store) {
  DCHECK(callback != NULL);
  DCHECK(cookie_store != NULL);

  int completion_callback_id = GetNextCompletionCallbackId();
  DCHECK(!ContainsKey(completion_callback_map_, completion_callback_id));

  CookieCompletionInfo cookie_info;
  cookie_info.completion_callback = callback;
  cookie_info.cookie_store = cookie_store;

  completion_callback_map_[completion_callback_id] = cookie_info;

  Send(new AutomationMsg_GetCookiesFromHost(0, tab_handle, url,
                                            completion_callback_id));
}

void AutomationResourceMessageFilter::OnGetCookiesHostResponse(
    int tab_handle, bool success, const GURL& url, const std::string& cookies,
    int cookie_id) {
  CompletionCallbackMap::iterator index =
      completion_callback_map_.find(cookie_id);
  if (index != completion_callback_map_.end()) {
    net::CompletionCallback* callback = index->second.completion_callback;
    scoped_refptr<net::CookieStore> cookie_store = index->second.cookie_store;

    DCHECK(callback != NULL);
    DCHECK(cookie_store.get() != NULL);

    completion_callback_map_.erase(index);

    // Set the cookie in the cookie store so that the callback can read it.
    cookie_store->SetCookieWithOptions(url, cookies, net::CookieOptions());

    Tuple1<int> params;
    params.a = success ? net::OK : net::ERR_ACCESS_DENIED;
    callback->RunWithParams(params);

    // The cookie for this URL is only valid until it is read by the callback.
    cookie_store->SetCookieWithOptions(url, "", net::CookieOptions());
  } else {
    NOTREACHED() << "Received invalid completion callback id:"
                 << cookie_id;
  }
}

// static
void AutomationResourceMessageFilter::ResumeJobsForPendingView(
    int tab_handle,
    AutomationResourceMessageFilter* old_filter,
    AutomationResourceMessageFilter* new_filter) {
  DCHECK(old_filter != NULL);
  DCHECK(new_filter != NULL);

  RequestMap pending_requests = old_filter->pending_request_map_;

  for (RequestMap::iterator index = old_filter->pending_request_map_.begin();
          index != old_filter->pending_request_map_.end(); index++) {
    scoped_refptr<URLRequestAutomationJob> job = (*index).second;
    DCHECK_EQ(job->message_filter(), old_filter);
    DCHECK(job->is_pending());
    // StartPendingJob will register the job with the new filter.
    job->StartPendingJob(tab_handle, new_filter);
  }

  old_filter->pending_request_map_.clear();
}
<commit_msg>Coverity issue 8296: Uninitialized member in automation_resource_message_filter.cc<commit_after>// Copyright (c) 2010 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/automation/automation_resource_message_filter.h"

#include "base/histogram.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/automation/url_request_automation_job.h"
#include "chrome/browser/net/url_request_failed_dns_job.h"
#include "chrome/browser/net/url_request_mock_http_job.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/net/url_request_slow_download_job.h"
#include "chrome/browser/net/url_request_slow_http_job.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/test/automation/automation_messages.h"
#include "googleurl/src/gurl.h"
#include "net/base/cookie_store.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_filter.h"

AutomationResourceMessageFilter::RenderViewMap
    AutomationResourceMessageFilter::filtered_render_views_;

int AutomationResourceMessageFilter::unique_request_id_ = 1;

AutomationResourceMessageFilter::AutomationResourceMessageFilter()
    : channel_(NULL),
      next_completion_callback_id_(0) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          URLRequestAutomationJob::EnsureProtocolFactoryRegistered));
}

AutomationResourceMessageFilter::~AutomationResourceMessageFilter() {
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
  DCHECK(channel_ == NULL);
  channel_ = channel;
}

void AutomationResourceMessageFilter::OnFilterRemoved() {
  channel_ = NULL;
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnChannelConnected(int32 peer_pid) {
}

// Called on the IPC thread:
void AutomationResourceMessageFilter::OnChannelClosing() {
  channel_ = NULL;
  request_map_.clear();

  // Only erase RenderViews which are associated with this
  // AutomationResourceMessageFilter instance.
  RenderViewMap::iterator index = filtered_render_views_.begin();
  while (index != filtered_render_views_.end()) {
    const AutomationDetails& details = (*index).second;
    if (details.filter.get() == this) {
      filtered_render_views_.erase(index++);
    } else {
      index++;
    }
  }
}

// Called on the IPC thread:
bool AutomationResourceMessageFilter::OnMessageReceived(
    const IPC::Message& message) {
  int request_id;
  if (URLRequestAutomationJob::MayFilterMessage(message, &request_id)) {
    RequestMap::iterator it = request_map_.find(request_id);
    if (it != request_map_.end()) {
      URLRequestAutomationJob* job = it->second;
      DCHECK(job);
      if (job) {
        job->OnMessage(message);
        return true;
      }
    }
  }

  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(AutomationResourceMessageFilter, message)
    IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet,
                        OnSetFilteredInet)
    IPC_MESSAGE_HANDLER(AutomationMsg_GetFilteredInetHitCount,
                        OnGetFilteredInetHitCount)
    IPC_MESSAGE_HANDLER(AutomationMsg_RecordHistograms,
                        OnRecordHistograms)
    IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesHostResponse,
                        OnGetCookiesHostResponse)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

// Called on the IPC thread:
bool AutomationResourceMessageFilter::Send(IPC::Message* message) {
  // This has to be called on the IO thread.
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  if (!channel_) {
    delete message;
    return false;
  }

  return channel_->Send(message);
}

bool AutomationResourceMessageFilter::RegisterRequest(
    URLRequestAutomationJob* job) {
  if (!job) {
    NOTREACHED();
    return false;
  }
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  // Register pending jobs in the pending request map for servicing later.
  if (job->is_pending()) {
    DCHECK(!ContainsKey(pending_request_map_, job->id()));
    DCHECK(!ContainsKey(request_map_, job->id()));
    pending_request_map_[job->id()] = job;
  } else {
    DCHECK(!ContainsKey(request_map_, job->id()));
    DCHECK(!ContainsKey(pending_request_map_, job->id()));
    request_map_[job->id()] = job;
  }

  return true;
}

void AutomationResourceMessageFilter::UnRegisterRequest(
    URLRequestAutomationJob* job) {
  if (!job) {
    NOTREACHED();
    return;
  }
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (job->is_pending()) {
    DCHECK(ContainsKey(pending_request_map_, job->id()));
    pending_request_map_.erase(job->id());
  } else {
    DCHECK(ContainsKey(request_map_, job->id()));
    request_map_.erase(job->id());
  }
}

bool AutomationResourceMessageFilter::RegisterRenderView(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter,
    bool pending_view) {
  if (!renderer_pid || !renderer_id || !tab_handle) {
    NOTREACHED();
    return false;
  }

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::RegisterRenderViewInIOThread,
          renderer_pid, renderer_id, tab_handle, filter, pending_view));
  return true;
}

void AutomationResourceMessageFilter::UnRegisterRenderView(
    int renderer_pid, int renderer_id) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread,
          renderer_pid, renderer_id));
}

bool AutomationResourceMessageFilter::ResumePendingRenderView(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter) {
  if (!renderer_pid || !renderer_id || !tab_handle) {
    NOTREACHED();
    return false;
  }

  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableFunction(
          AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread,
          renderer_pid, renderer_id, tab_handle, filter));
  return true;
}

void AutomationResourceMessageFilter::RegisterRenderViewInIOThread(
    int renderer_pid, int renderer_id,
    int tab_handle, AutomationResourceMessageFilter* filter,
    bool pending_view) {
  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));
  if (automation_details_iter != filtered_render_views_.end()) {
    DCHECK(automation_details_iter->second.ref_count > 0);
    automation_details_iter->second.ref_count++;
  } else {
    filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
        AutomationDetails(tab_handle, filter, pending_view);
  }
}

// static
void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread(
    int renderer_pid, int renderer_id) {
  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));

  if (automation_details_iter == filtered_render_views_.end()) {
    LOG(INFO) << "UnRegisterRenderViewInIOThread: already unregistered";
    return;
  }

  automation_details_iter->second.ref_count--;

  if (automation_details_iter->second.ref_count <= 0) {
    filtered_render_views_.erase(RendererId(renderer_pid, renderer_id));
  }
}

// static
bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread(
    int renderer_pid, int renderer_id, int tab_handle,
    AutomationResourceMessageFilter* filter) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  RenderViewMap::iterator automation_details_iter(
      filtered_render_views_.find(RendererId(renderer_pid, renderer_id)));

  if (automation_details_iter == filtered_render_views_.end()) {
    NOTREACHED() << "Failed to find pending view for renderer pid:"
                 << renderer_pid
                 << ", render view id:"
                 << renderer_id;
    return false;
  }

  DCHECK(automation_details_iter->second.is_pending_render_view);

  AutomationResourceMessageFilter* old_filter =
      automation_details_iter->second.filter;
  DCHECK(old_filter != NULL);

  filtered_render_views_[RendererId(renderer_pid, renderer_id)] =
      AutomationDetails(tab_handle, filter, false);

  ResumeJobsForPendingView(tab_handle, old_filter, filter);
  return true;
}

bool AutomationResourceMessageFilter::LookupRegisteredRenderView(
    int renderer_pid, int renderer_id, AutomationDetails* details) {
  bool found = false;
  RenderViewMap::iterator it = filtered_render_views_.find(RendererId(
      renderer_pid, renderer_id));
  if (it != filtered_render_views_.end()) {
    found = true;
    if (details)
      *details = it->second;
  }

  return found;
}

bool AutomationResourceMessageFilter::GetAutomationRequestId(
    int request_id, int* automation_request_id) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  RequestMap::iterator it = request_map_.begin();
  while (it != request_map_.end()) {
    URLRequestAutomationJob* job = it->second;
    DCHECK(job);
    if (job && job->request_id() == request_id) {
      *automation_request_id = job->id();
      return true;
    }
    it++;
  }

  return false;
}

bool AutomationResourceMessageFilter::SendDownloadRequestToHost(
    int routing_id, int tab_handle, int request_id) {
  int automation_request_id = 0;
  bool valid_id = GetAutomationRequestId(request_id, &automation_request_id);
  if (!valid_id) {
    NOTREACHED() << "Invalid request id: " << request_id;
    return false;
  }

  return Send(new AutomationMsg_DownloadRequestInHost(0, tab_handle,
                                                      automation_request_id));
}

void AutomationResourceMessageFilter::OnSetFilteredInet(bool enable) {
  chrome_browser_net::SetUrlRequestMocksEnabled(enable);
}

void AutomationResourceMessageFilter::OnGetFilteredInetHitCount(
    int* hit_count) {
  *hit_count = URLRequestFilter::GetInstance()->hit_count();
}

void AutomationResourceMessageFilter::OnRecordHistograms(
    const std::vector<std::string>& histogram_list) {
  for (size_t index = 0; index < histogram_list.size(); ++index) {
    Histogram::DeserializeHistogramInfo(histogram_list[index]);
  }
}

void AutomationResourceMessageFilter::GetCookiesForUrl(
    int tab_handle, const GURL& url, net::CompletionCallback* callback,
    net::CookieStore* cookie_store) {
  DCHECK(callback != NULL);
  DCHECK(cookie_store != NULL);

  int completion_callback_id = GetNextCompletionCallbackId();
  DCHECK(!ContainsKey(completion_callback_map_, completion_callback_id));

  CookieCompletionInfo cookie_info;
  cookie_info.completion_callback = callback;
  cookie_info.cookie_store = cookie_store;

  completion_callback_map_[completion_callback_id] = cookie_info;

  Send(new AutomationMsg_GetCookiesFromHost(0, tab_handle, url,
                                            completion_callback_id));
}

void AutomationResourceMessageFilter::OnGetCookiesHostResponse(
    int tab_handle, bool success, const GURL& url, const std::string& cookies,
    int cookie_id) {
  CompletionCallbackMap::iterator index =
      completion_callback_map_.find(cookie_id);
  if (index != completion_callback_map_.end()) {
    net::CompletionCallback* callback = index->second.completion_callback;
    scoped_refptr<net::CookieStore> cookie_store = index->second.cookie_store;

    DCHECK(callback != NULL);
    DCHECK(cookie_store.get() != NULL);

    completion_callback_map_.erase(index);

    // Set the cookie in the cookie store so that the callback can read it.
    cookie_store->SetCookieWithOptions(url, cookies, net::CookieOptions());

    Tuple1<int> params;
    params.a = success ? net::OK : net::ERR_ACCESS_DENIED;
    callback->RunWithParams(params);

    // The cookie for this URL is only valid until it is read by the callback.
    cookie_store->SetCookieWithOptions(url, "", net::CookieOptions());
  } else {
    NOTREACHED() << "Received invalid completion callback id:"
                 << cookie_id;
  }
}

// static
void AutomationResourceMessageFilter::ResumeJobsForPendingView(
    int tab_handle,
    AutomationResourceMessageFilter* old_filter,
    AutomationResourceMessageFilter* new_filter) {
  DCHECK(old_filter != NULL);
  DCHECK(new_filter != NULL);

  RequestMap pending_requests = old_filter->pending_request_map_;

  for (RequestMap::iterator index = old_filter->pending_request_map_.begin();
          index != old_filter->pending_request_map_.end(); index++) {
    scoped_refptr<URLRequestAutomationJob> job = (*index).second;
    DCHECK_EQ(job->message_filter(), old_filter);
    DCHECK(job->is_pending());
    // StartPendingJob will register the job with the new filter.
    job->StartPendingJob(tab_handle, new_filter);
  }

  old_filter->pending_request_map_.clear();
}
<|endoftext|>