<commit_before>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Henri I Hyyryläinen (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/RendererModules/Ogre/GeometryBuffer.h"
#include "CEGUI/RendererModules/Ogre/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/RenderEffect.h"

#include <OgreRenderSystem.h>
#include <OgreQuaternion.h>
#include <OgreHardwareBufferManager.h>
#include "CEGUI/Exceptions.h"
#include "CEGUI/ShaderParameterBindings.h"

#include "OgreManualObject.h"
#include "OgreRenderOperation.h"
#include "OgreSceneManager.h"

#define INITIAL_BUFFER_SIZE     64

#define FLOATS_PER_TEXTURED     9
#define FLOATS_PER_COLOURED     7

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_colourBlendMode =
{
    Ogre::LBT_COLOUR,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE,
    Ogre::ColourValue(0, 0, 0, 0),
    Ogre::ColourValue(0, 0, 0, 0),
    0, 0, 0
};

//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_alphaBlendMode =
{
    Ogre::LBT_ALPHA,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE,
    Ogre::ColourValue(0, 0, 0, 0),
    Ogre::ColourValue(0, 0, 0, 0),
    0, 0, 0
};

//----------------------------------------------------------------------------//
static const Ogre::TextureUnitState::UVWAddressingMode S_textureAddressMode =
{
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP
};

//----------------------------------------------------------------------------//
OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
    Ogre::RenderSystem& rs, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    GeometryBuffer(renderMaterial),
    d_owner(owner),
    d_renderSystem(rs),
    d_clipRect(0, 0, 0, 0),
    d_matrixValid(false),
    d_vertexHolder(0),
    d_expectedData(MANUALOBJECT_TYPE_INVALID),
    d_renderOp(0),
    d_dataAppended(false)
{

}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanUpVertexAttributes();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    if (d_vertexData.empty() || !d_renderOp)
        return;

    if (d_dataAppended)
        syncManualObject();

    // setup clip region
    if (d_clippingActive)
        setScissorRects();

    // Update the model matrix if necessary
    if (!d_matrixValid)
        updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings =
        (*d_renderMaterial).getShaderParamBindings();

    // Set the ModelViewProjection matrix in the bindings
    Ogre::Matrix4 omat = d_owner.getWorldViewProjMatrix()*d_matrix;

    glm::mat4 glmmat;

    OgreRenderer::convertOgreMatrixToGLMMatrix(omat, glmmat);

    shaderParameterBindings->setParameter("modelViewPerspMatrix", glmmat);

    d_owner.bindBlendMode(d_blendMode);

    bool found_texture = false;

    // Not sure if this is needed here
    const ShaderParameterBindings::ShaderParameterBindingsMap&
        shader_parameter_bindings = shaderParameterBindings->
        getShaderParameterBindings();

    ShaderParameterBindings::ShaderParameterBindingsMap::const_iterator iter =
        shader_parameter_bindings.begin();
    ShaderParameterBindings::ShaderParameterBindingsMap::const_iterator end =
        shader_parameter_bindings.end();

    while(iter != end)
    {
        const CEGUI::ShaderParameter* parameter = iter->second;
        const ShaderParamType parameterType = parameter->getType();

        if (iter->first == "texture0")
        {

            const CEGUI::ShaderParameterTexture* parameterTexture =
                static_cast<const CEGUI::ShaderParameterTexture*>(parameter);

            const CEGUI::OgreTexture* texture = static_cast<const
                CEGUI::OgreTexture*>(parameterTexture->d_parameterValue);

            d_vertexHolder->setMaterialName(0,
                texture->getOgreTexture()->getName());

            found_texture = true;
            break;
        }
    }

    if (!found_texture)
    {
        // Reset the material
        d_vertexHolder->setMaterialName(0, "BaseWhiteNoLighting");
    }

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        initialiseTextureStates();

        //Prepare for the rendering process according to the used render material
        d_renderMaterial->prepareForRendering();

        // draw the geometry
        d_renderSystem._render(*d_renderOp);
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clipRect.top(ceguimax(0.0f, region.top()));
    d_clipRect.bottom(ceguimax(0.0f, region.bottom()));
    d_clipRect.left(ceguimax(0.0f, region.left()));
    d_clipRect.right(ceguimax(0.0f, region.right()));
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const std::vector<float>& vertex_data)
{
    d_vertexData.insert(d_vertexData.end(), vertex_data.begin(),
        vertex_data.end());

    d_dataAppended = true;

    size_t float_per_element;

    switch(d_expectedData){
    case MANUALOBJECT_TYPE_COLOURED: float_per_element = FLOATS_PER_COLOURED; break;
    case MANUALOBJECT_TYPE_TEXTURED: float_per_element = FLOATS_PER_TEXTURED; break;
    }

    d_vertexCount = d_vertexData.size()/float_per_element;
}

void OgreGeometryBuffer::syncManualObject() const
{
    if (!d_dataAppended)
        return;

    // All the data is in the vector so it's safe to clear
    d_vertexHolder->clear();

    // Blank material initially
    d_vertexHolder->begin("BaseWhiteNoLighting",
        Ogre::RenderOperation::OT_TRIANGLE_LIST);

    // Append the data to the manual object
    if (d_expectedData == MANUALOBJECT_TYPE_TEXTURED)
    {
        for (size_t i = 0; i < d_vertexData.size(); i += FLOATS_PER_TEXTURED)
        {
            assert(i+FLOATS_PER_TEXTURED < d_vertexData.size() &&
                "invalid vertex data passed to OgreGeometryBuffer");

            // First the position
            d_vertexHolder->position(d_vertexData[i], d_vertexData[i+1],
                d_vertexData[i+2]);

            // And then the colour
            d_vertexHolder->colour(d_vertexData[i+3], d_vertexData[i+4],
                d_vertexData[i+5], d_vertexData[i+6]);

            // And finally texture coordinate
            d_vertexHolder->textureCoord(d_vertexData[i+7], d_vertexData[i+8]);
        }
    }
    else if (d_expectedData == MANUALOBJECT_TYPE_COLOURED)
    {

        for (size_t i = 0; i < d_vertexData.size(); i += FLOATS_PER_COLOURED)
        {
            assert(i+FLOATS_PER_COLOURED < d_vertexData.size() &&
                "invalid vertex data passed to OgreGeometryBuffer");

            // First the position
            d_vertexHolder->position(d_vertexData[i], d_vertexData[i+1],
                d_vertexData[i+2]);

            // And then the colour
            d_vertexHolder->colour(d_vertexData[i+3], d_vertexData[i+4],
                d_vertexData[i+5], d_vertexData[i+6]);
        }
    }

    auto section = d_vertexHolder->end();

    d_renderOp = section->getRenderOperation();

    d_dataAppended = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;

    trans.makeTrans(d_translation.d_x + d_pivot.d_x,
        d_translation.d_y + d_pivot.d_y,
        d_translation.d_z + d_pivot.d_z);

    // rotation
    Ogre::Matrix4 rot(Ogre::Quaternion(
        d_rotation.d_w, d_rotation.d_x, d_rotation.d_y, d_rotation.d_z));

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.d_x, -d_pivot.d_y, -d_pivot.d_z);

    // calculate final matrix
    d_matrix = trans * rot * inv_pivot_trans;

    d_matrixValid = true;
}

//----------------------------------------------------------------------------//
const Ogre::Matrix4& OgreGeometryBuffer::getMatrix() const{
    if (!d_matrixValid)
        updateMatrix();

    return d_matrix;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::initialiseTextureStates() const
{
    using namespace Ogre;
    d_renderSystem._setTextureCoordCalculation(0, TEXCALC_NONE);
    d_renderSystem._setTextureCoordSet(0, 0);
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
    d_renderSystem._setTextureAddressingMode(0, S_textureAddressMode);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0, false);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::finaliseVertexAttributes(MANUALOBJECT_TYPE type)
{
    d_expectedData = type;

    if (d_expectedData >= MANUALOBJECT_TYPE_INVALID)
    {
        CEGUI_THROW(RendererException(
            "Unknown d_expectedData type."));
    }

    setVertexBuffer(INITIAL_BUFFER_SIZE);
}

void OgreGeometryBuffer::setVertexBuffer(size_t size)
{
    // create the vertex container
    d_vertexHolder = d_owner.getDummyScene().createManualObject(
        Ogre::SCENE_STATIC);

    if (!d_vertexHolder)
    {
        CEGUI_THROW(RendererException("Failed to create Ogre vertex buffer, "
            "probably because the vertex layout is invalid."));
    }

    d_vertexHolder->setDynamic(false);
    d_vertexHolder->estimateVertexCount(size);
}

void OgreGeometryBuffer::cleanUpVertexAttributes()
{
    d_renderOp = 0;

    d_owner.getDummyScene().destroyManualObject(d_vertexHolder);
    d_vertexHolder = 0;
}

void OgreGeometryBuffer::setScissorRects() const
{
    d_renderSystem.setScissorTest(true, d_clipRect.left(),
        d_clipRect.top(), d_clipRect.right(), d_clipRect.bottom());
}

} // End of  CEGUI namespace section
<commit_msg>IT WORKS! at least the loading screen displays<commit_after>/***********************************************************************
    created:    Tue Feb 17 2009
    author:     Henri I Hyyryläinen (based on code by Paul D Turner)
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUI/RendererModules/Ogre/GeometryBuffer.h"
#include "CEGUI/RendererModules/Ogre/Texture.h"
#include "CEGUI/Vertex.h"
#include "CEGUI/RenderEffect.h"

#include <OgreRenderSystem.h>
#include <OgreQuaternion.h>
#include <OgreHardwareBufferManager.h>
#include "CEGUI/Exceptions.h"
#include "CEGUI/ShaderParameterBindings.h"

#include "OgreManualObject.h"
#include "OgreRenderOperation.h"
#include "OgreSceneManager.h"

#define INITIAL_BUFFER_SIZE     64

#define FLOATS_PER_TEXTURED     9
#define FLOATS_PER_COLOURED     7

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_colourBlendMode =
{
    Ogre::LBT_COLOUR,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE,
    Ogre::ColourValue(0, 0, 0, 0),
    Ogre::ColourValue(0, 0, 0, 0),
    0, 0, 0
};

//----------------------------------------------------------------------------//
static const Ogre::LayerBlendModeEx S_alphaBlendMode =
{
    Ogre::LBT_ALPHA,
    Ogre::LBX_MODULATE,
    Ogre::LBS_TEXTURE,
    Ogre::LBS_DIFFUSE,
    Ogre::ColourValue(0, 0, 0, 0),
    Ogre::ColourValue(0, 0, 0, 0),
    0, 0, 0
};

//----------------------------------------------------------------------------//
static const Ogre::TextureUnitState::UVWAddressingMode S_textureAddressMode =
{
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP,
    Ogre::TextureUnitState::TAM_CLAMP
};

//----------------------------------------------------------------------------//
OgreGeometryBuffer::OgreGeometryBuffer(OgreRenderer& owner,
    Ogre::RenderSystem& rs, CEGUI::RefCounted<RenderMaterial> renderMaterial) :
    GeometryBuffer(renderMaterial),
    d_owner(owner),
    d_renderSystem(rs),
    d_clipRect(0, 0, 0, 0),
    d_matrixValid(false),
    d_vertexHolder(0),
    d_expectedData(MANUALOBJECT_TYPE_INVALID),
    d_renderOp(0),
    d_dataAppended(false)
{

}

//----------------------------------------------------------------------------//
OgreGeometryBuffer::~OgreGeometryBuffer()
{
    cleanUpVertexAttributes();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::draw() const
{
    if (d_vertexData.empty())
        return;

    if (d_dataAppended)
        syncManualObject();

    if (!d_renderOp)
        return;

    // setup clip region
    if (d_clippingActive)
        setScissorRects();

    // Update the model matrix if necessary
    if (!d_matrixValid)
        updateMatrix();

    CEGUI::ShaderParameterBindings* shaderParameterBindings =
        (*d_renderMaterial).getShaderParamBindings();

    // Set the ModelViewProjection matrix in the bindings
    Ogre::Matrix4 omat = d_owner.getWorldViewProjMatrix()*d_matrix;

    glm::mat4 glmmat;

    OgreRenderer::convertOgreMatrixToGLMMatrix(omat, glmmat);

    shaderParameterBindings->setParameter("modelViewPerspMatrix", glmmat);

    d_owner.bindBlendMode(d_blendMode);

    bool found_texture = false;

    // Not sure if this is needed here
    const ShaderParameterBindings::ShaderParameterBindingsMap&
        shader_parameter_bindings = shaderParameterBindings->
        getShaderParameterBindings();

    auto end = shader_parameter_bindings.end();

    for (auto iter = shader_parameter_bindings.begin(); iter != end; ++iter)
    {
        const CEGUI::ShaderParameter* parameter = iter->second;
        const ShaderParamType parameterType = parameter->getType();

        if (iter->first == "texture0")
        {

            const CEGUI::ShaderParameterTexture* parameterTexture =
                static_cast<const CEGUI::ShaderParameterTexture*>(parameter);

            const CEGUI::OgreTexture* texture = static_cast<const
                CEGUI::OgreTexture*>(parameterTexture->d_parameterValue);

            d_vertexHolder->setMaterialName(0,
                texture->getOgreTexture()->getName());

            found_texture = true;
            break;
        }
    }

    if (!found_texture)
    {
        // Reset the material
        d_vertexHolder->setMaterialName(0, "BaseWhiteNoLighting");
    }

    const int pass_count = d_effect ? d_effect->getPassCount() : 1;
    for (int pass = 0; pass < pass_count; ++pass)
    {
        // set up RenderEffect
        if (d_effect)
            d_effect->performPreRenderFunctions(pass);

        initialiseTextureStates();

        //Prepare for the rendering process according to the used render material
        d_renderMaterial->prepareForRendering();

        // draw the geometry
        d_renderSystem._render(*d_renderOp);
    }

    // clean up RenderEffect
    if (d_effect)
        d_effect->performPostRenderFunctions();
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::setClippingRegion(const Rectf& region)
{
    d_clipRect.top(ceguimax(0.0f, region.top()));
    d_clipRect.bottom(ceguimax(0.0f, region.bottom()));
    d_clipRect.left(ceguimax(0.0f, region.left()));
    d_clipRect.right(ceguimax(0.0f, region.right()));
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::appendGeometry(const std::vector<float>& vertex_data)
{
    d_vertexData.insert(d_vertexData.end(), vertex_data.begin(),
        vertex_data.end());

    d_dataAppended = true;

    size_t float_per_element;

    switch(d_expectedData){
    case MANUALOBJECT_TYPE_COLOURED: float_per_element = FLOATS_PER_COLOURED; break;
    case MANUALOBJECT_TYPE_TEXTURED: float_per_element = FLOATS_PER_TEXTURED; break;
    }

    d_vertexCount = d_vertexData.size()/float_per_element;
}

void OgreGeometryBuffer::syncManualObject() const
{
    if (!d_dataAppended)
        return;

    // All the data is in the vector so it's safe to clear
    d_vertexHolder->clear();

    // Blank material initially
    d_vertexHolder->begin("BaseWhiteNoLighting",
        Ogre::RenderOperation::OT_TRIANGLE_LIST);

    // Append the data to the manual object
    if (d_expectedData == MANUALOBJECT_TYPE_TEXTURED)
    {
        for (size_t i = 0; i < d_vertexData.size(); i += FLOATS_PER_TEXTURED)
        {
            assert(i+FLOATS_PER_TEXTURED <= d_vertexData.size() &&
                "invalid vertex data passed to OgreGeometryBuffer");

            // First the position
            d_vertexHolder->position(d_vertexData[i], d_vertexData[i+1],
                d_vertexData[i+2]);

            // And then the colour
            d_vertexHolder->colour(d_vertexData[i+3], d_vertexData[i+4],
                d_vertexData[i+5], d_vertexData[i+6]);

            // And finally texture coordinate
            d_vertexHolder->textureCoord(d_vertexData[i+7], d_vertexData[i+8]);
        }
    }
    else if (d_expectedData == MANUALOBJECT_TYPE_COLOURED)
    {

        for (size_t i = 0; i < d_vertexData.size(); i += FLOATS_PER_COLOURED)
        {
            assert(i+FLOATS_PER_COLOURED <= d_vertexData.size() &&
                "invalid vertex data passed to OgreGeometryBuffer");

            // First the position
            d_vertexHolder->position(d_vertexData[i], d_vertexData[i+1],
                d_vertexData[i+2]);

            // And then the colour
            d_vertexHolder->colour(d_vertexData[i+3], d_vertexData[i+4],
                d_vertexData[i+5], d_vertexData[i+6]);
        }
    }

    auto section = d_vertexHolder->end();

    d_renderOp = section->getRenderOperation();

    d_dataAppended = false;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::updateMatrix() const
{
    // translation to position geometry and offset to pivot point
    Ogre::Matrix4 trans;

    trans.makeTrans(d_translation.d_x + d_pivot.d_x,
        d_translation.d_y + d_pivot.d_y,
        d_translation.d_z + d_pivot.d_z);

    // rotation
    Ogre::Matrix4 rot(Ogre::Quaternion(
        d_rotation.d_w, d_rotation.d_x, d_rotation.d_y, d_rotation.d_z));

    // translation to remove rotation pivot offset
    Ogre::Matrix4 inv_pivot_trans;
    inv_pivot_trans.makeTrans(-d_pivot.d_x, -d_pivot.d_y, -d_pivot.d_z);

    // calculate final matrix
    d_matrix = trans * rot * inv_pivot_trans;

    d_matrixValid = true;
}

//----------------------------------------------------------------------------//
const Ogre::Matrix4& OgreGeometryBuffer::getMatrix() const{
    if (!d_matrixValid)
        updateMatrix();

    return d_matrix;
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::initialiseTextureStates() const
{
    using namespace Ogre;
    d_renderSystem._setTextureCoordCalculation(0, TEXCALC_NONE);
    d_renderSystem._setTextureCoordSet(0, 0);
    d_renderSystem._setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
    d_renderSystem._setTextureAddressingMode(0, S_textureAddressMode);
    d_renderSystem._setTextureMatrix(0, Matrix4::IDENTITY);
    d_renderSystem._setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0, false);
    d_renderSystem._setTextureBlendMode(0, S_colourBlendMode);
    d_renderSystem._setTextureBlendMode(0, S_alphaBlendMode);
    d_renderSystem._disableTextureUnitsFrom(1);
}

//----------------------------------------------------------------------------//
void OgreGeometryBuffer::finaliseVertexAttributes(MANUALOBJECT_TYPE type)
{
    d_expectedData = type;

    if (d_expectedData >= MANUALOBJECT_TYPE_INVALID)
    {
        CEGUI_THROW(RendererException(
            "Unknown d_expectedData type."));
    }

    setVertexBuffer(INITIAL_BUFFER_SIZE);
}

void OgreGeometryBuffer::setVertexBuffer(size_t size)
{
    // create the vertex container
    d_vertexHolder = d_owner.getDummyScene().createManualObject(
        Ogre::SCENE_STATIC);

    if (!d_vertexHolder)
    {
        CEGUI_THROW(RendererException("Failed to create Ogre vertex buffer, "
            "probably because the vertex layout is invalid."));
    }

    d_vertexHolder->setDynamic(false);
    d_vertexHolder->estimateVertexCount(size);
}

void OgreGeometryBuffer::cleanUpVertexAttributes()
{
    d_renderOp = 0;

    d_owner.getDummyScene().destroyManualObject(d_vertexHolder);
    d_vertexHolder = 0;
}

void OgreGeometryBuffer::setScissorRects() const
{
    d_renderSystem.setScissorTest(true, d_clipRect.left(),
        d_clipRect.top(), d_clipRect.right(), d_clipRect.bottom());
}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/chromeos/login/touch_login_view.h"

#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/gfx/transform.h"
#include "views/controls/textfield/textfield.h"
#include "views/widget/widget.h"

namespace {

const char kViewClassName[] = "browser/chromeos/login/TouchLoginView";
const int kDefaultKeyboardHeight = 300;
const int kKeyboardSlideDuration = 300;  // In milliseconds

PropertyAccessor<bool>* GetFocusedStateAccessor() {
  static PropertyAccessor<bool> state;
  return &state;
}

bool TabContentsHasFocus(const TabContents* contents) {
  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
  return view->Contains(view->GetFocusManager()->GetFocusedView());
}

}  // namespace

namespace chromeos {

// TouchLoginView public: ------------------------------------------------------

TouchLoginView::TouchLoginView()
    : WebUILoginView(),
      keyboard_showing_(false),
      keyboard_height_(kDefaultKeyboardHeight),
      focus_listener_added_(false),
      keyboard_(NULL) {
}

TouchLoginView::~TouchLoginView() {
}

void TouchLoginView::Init() {
  WebUILoginView::Init();
  InitStatusArea();
  InitVirtualKeyboard();

  registrar_.Add(this,
                 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
                 NotificationService::AllSources());
}

std::string TouchLoginView::GetClassName() const {
  return kViewClassName;
}

void TouchLoginView::FocusWillChange(views::View* focused_before,
                                     views::View* focused_now) {
  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
  if (before != now) {
    // TODO(varunjain): support other types of keyboard.
    UpdateKeyboardAndLayout(now == GENERIC);
  }
}

void TouchLoginView::OnWindowCreated() {
}

// TouchLoginView protected: ---------------------------------------------------

void TouchLoginView::Layout() {
  WebUILoginView::Layout();
  DCHECK(status_area_);

  // Layout the Status Area up in the right corner. This should always be done.
  gfx::Size status_area_size = status_area_->GetPreferredSize();
  status_area_->SetBounds(
      width() - status_area_size.width() -
          WebUILoginView::kStatusAreaCornerPadding,
      WebUILoginView::kStatusAreaCornerPadding,
      status_area_size.width(),
      status_area_size.height());

  if (!keyboard_)
    return;

  // We are not resizing the DOMView here, so the keyboard is going to occlude
  // the login screen partially. It is the responsibility of the UX layer to
  // handle this.

  // Lastly layout the keyboard
  bool display_keyboard = (keyboard_showing_ || animation_->is_animating());
  keyboard_->SetVisible(display_keyboard);
  gfx::Rect keyboard_bounds = bounds();
  int keyboard_height = display_keyboard ? keyboard_height_ : 0;
  keyboard_bounds.set_y(keyboard_bounds.height() - keyboard_height);
  keyboard_bounds.set_height(keyboard_height);
  keyboard_->SetBoundsRect(keyboard_bounds);
}

void TouchLoginView::InitStatusArea() {
  if (status_area_)
    return;
  status_area_ = new StatusAreaView(this);
  status_area_->Init();
  AddChildView(status_area_);
}

// TouchLoginView private: -----------------------------------------------------

void TouchLoginView::InitVirtualKeyboard() {
  keyboard_ = new KeyboardContainerView(profile_, NULL);
  keyboard_->SetVisible(false);
  AddChildView(keyboard_);

  animation_.reset(new ui::SlideAnimation(this));
  animation_->SetTweenType(ui::Tween::LINEAR);
  animation_->SetSlideDuration(kKeyboardSlideDuration);
}

void TouchLoginView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
  DCHECK(keyboard_);
  if (should_show_keyboard == keyboard_showing_)
    return;
  keyboard_showing_ = should_show_keyboard;
  if (keyboard_showing_) {
    ui::Transform transform;
    transform.SetTranslateY(-keyboard_height_);
    keyboard_->SetTransform(transform);
    Layout();
    animation_->Show();
  } else {
    ui::Transform transform;
    keyboard_->SetTransform(transform);
    animation_->Hide();
    Layout();
  }
}

TouchLoginView::VirtualKeyboardType
    TouchLoginView::DecideKeyboardStateForView(views::View* view) {
  if (!view)
    return NONE;

  std::string cname = view->GetClassName();
  if (cname == views::Textfield::kViewClassName) {
    return GENERIC;
  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
    TabContents* contents = webui_login_->tab_contents();
    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
        contents->property_bag()) : NULL;
    if (editable && *editable)
      return GENERIC;
  }
  return NONE;
}

void TouchLoginView::Observe(int type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) {
    // Only modify the keyboard state if the currently active tab sent the
    // notification.
    const TabContents* current_tab = webui_login_->tab_contents();
    TabContents* source_tab = Source<TabContents>(source).ptr();
    const bool editable = *Details<const bool>(details).ptr();

    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
      UpdateKeyboardAndLayout(editable);

    // Save the state of the focused field so that the keyboard visibility
    // can be determined after tab switching.
    GetFocusedStateAccessor()->SetProperty(
        source_tab->property_bag(), editable);
  } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) {
    GetFocusedStateAccessor()->DeleteProperty(
        Source<TabContents>(source).ptr()->property_bag());
  } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) {
    UpdateKeyboardAndLayout(false);
  } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) {
    // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
    // instead of using Notification.
    int height = *(Details<int>(details).ptr());
    if (height != keyboard_height_) {
      DCHECK_GE(height, 0) << "Height of the keyboard is less than 0.";
      DCHECK_LE(height, View::height()) << "Height of the keyboard is greater "
          "than the height of containing view.";
      keyboard_height_ = height;
      Layout();
    }
  }
}

// ui::AnimationDelegate implementation ----------------------------------------

void TouchLoginView::AnimationProgressed(const ui::Animation* anim) {
  ui::Transform transform;
  transform.SetTranslateY(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0));
  keyboard_->SetTransform(transform);
}

void TouchLoginView::AnimationEnded(const ui::Animation* animation) {
  if (keyboard_showing_) {
    Layout();
  } else {
    // Notify the keyboard that it is hidden now.
    keyboard_->SetVisible(false);
  }
}

}  // namespace chromeos
<commit_msg>Profiles: Fix touchui usage of AllSources() for FOCUS_CHANGED_IN_PAGE.<commit_after>// Copyright (c) 2011 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/chromeos/login/touch_login_view.h"

#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/render_widget_host_view_views.h"
#include "chrome/browser/ui/touch/frame/keyboard_container_view.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_touch.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/gfx/transform.h"
#include "views/controls/textfield/textfield.h"
#include "views/widget/widget.h"

namespace {

const char kViewClassName[] = "browser/chromeos/login/TouchLoginView";
const int kDefaultKeyboardHeight = 300;
const int kKeyboardSlideDuration = 300;  // In milliseconds

PropertyAccessor<bool>* GetFocusedStateAccessor() {
  static PropertyAccessor<bool> state;
  return &state;
}

bool TabContentsHasFocus(const TabContents* contents) {
  views::View* view = static_cast<TabContentsViewTouch*>(contents->view());
  return view->Contains(view->GetFocusManager()->GetFocusedView());
}

}  // namespace

namespace chromeos {

// TouchLoginView public: ------------------------------------------------------

TouchLoginView::TouchLoginView()
    : WebUILoginView(),
      keyboard_showing_(false),
      keyboard_height_(kDefaultKeyboardHeight),
      focus_listener_added_(false),
      keyboard_(NULL) {
}

TouchLoginView::~TouchLoginView() {
}

void TouchLoginView::Init() {
  WebUILoginView::Init();
  InitStatusArea();
  InitVirtualKeyboard();

  Source<TabContents> tab_contents(webui_login_->tab_contents()));
  registrar_.Add(this,
                 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
                 tab_contents);
  registrar_.Add(this,
                 content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
                 tab_contents);
  registrar_.Add(this,
                 chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED,
                 NotificationService::AllSources());
  registrar_.Add(this,
                 chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED,
                 NotificationService::AllSources());
}

std::string TouchLoginView::GetClassName() const {
  return kViewClassName;
}

void TouchLoginView::FocusWillChange(views::View* focused_before,
                                     views::View* focused_now) {
  VirtualKeyboardType before = DecideKeyboardStateForView(focused_before);
  VirtualKeyboardType now = DecideKeyboardStateForView(focused_now);
  if (before != now) {
    // TODO(varunjain): support other types of keyboard.
    UpdateKeyboardAndLayout(now == GENERIC);
  }
}

void TouchLoginView::OnWindowCreated() {
}

// TouchLoginView protected: ---------------------------------------------------

void TouchLoginView::Layout() {
  WebUILoginView::Layout();
  DCHECK(status_area_);

  // Layout the Status Area up in the right corner. This should always be done.
  gfx::Size status_area_size = status_area_->GetPreferredSize();
  status_area_->SetBounds(
      width() - status_area_size.width() -
          WebUILoginView::kStatusAreaCornerPadding,
      WebUILoginView::kStatusAreaCornerPadding,
      status_area_size.width(),
      status_area_size.height());

  if (!keyboard_)
    return;

  // We are not resizing the DOMView here, so the keyboard is going to occlude
  // the login screen partially. It is the responsibility of the UX layer to
  // handle this.

  // Lastly layout the keyboard
  bool display_keyboard = (keyboard_showing_ || animation_->is_animating());
  keyboard_->SetVisible(display_keyboard);
  gfx::Rect keyboard_bounds = bounds();
  int keyboard_height = display_keyboard ? keyboard_height_ : 0;
  keyboard_bounds.set_y(keyboard_bounds.height() - keyboard_height);
  keyboard_bounds.set_height(keyboard_height);
  keyboard_->SetBoundsRect(keyboard_bounds);
}

void TouchLoginView::InitStatusArea() {
  if (status_area_)
    return;
  status_area_ = new StatusAreaView(this);
  status_area_->Init();
  AddChildView(status_area_);
}

// TouchLoginView private: -----------------------------------------------------

void TouchLoginView::InitVirtualKeyboard() {
  keyboard_ = new KeyboardContainerView(profile_, NULL);
  keyboard_->SetVisible(false);
  AddChildView(keyboard_);

  animation_.reset(new ui::SlideAnimation(this));
  animation_->SetTweenType(ui::Tween::LINEAR);
  animation_->SetSlideDuration(kKeyboardSlideDuration);
}

void TouchLoginView::UpdateKeyboardAndLayout(bool should_show_keyboard) {
  DCHECK(keyboard_);
  if (should_show_keyboard == keyboard_showing_)
    return;
  keyboard_showing_ = should_show_keyboard;
  if (keyboard_showing_) {
    ui::Transform transform;
    transform.SetTranslateY(-keyboard_height_);
    keyboard_->SetTransform(transform);
    Layout();
    animation_->Show();
  } else {
    ui::Transform transform;
    keyboard_->SetTransform(transform);
    animation_->Hide();
    Layout();
  }
}

TouchLoginView::VirtualKeyboardType
    TouchLoginView::DecideKeyboardStateForView(views::View* view) {
  if (!view)
    return NONE;

  std::string cname = view->GetClassName();
  if (cname == views::Textfield::kViewClassName) {
    return GENERIC;
  } else if (cname == RenderWidgetHostViewViews::kViewClassName) {
    TabContents* contents = webui_login_->tab_contents();
    bool* editable = contents ? GetFocusedStateAccessor()->GetProperty(
        contents->property_bag()) : NULL;
    if (editable && *editable)
      return GENERIC;
  }
  return NONE;
}

void TouchLoginView::Observe(int type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  if (type == content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE) {
    // Only modify the keyboard state if the currently active tab sent the
    // notification.
    const TabContents* current_tab = webui_login_->tab_contents();
    TabContents* source_tab = Source<TabContents>(source).ptr();
    const bool editable = *Details<const bool>(details).ptr();

    if (current_tab == source_tab && TabContentsHasFocus(source_tab))
      UpdateKeyboardAndLayout(editable);

    // Save the state of the focused field so that the keyboard visibility
    // can be determined after tab switching.
    GetFocusedStateAccessor()->SetProperty(
        source_tab->property_bag(), editable);
  } else if (type == content::NOTIFICATION_TAB_CONTENTS_DESTROYED) {
    GetFocusedStateAccessor()->DeleteProperty(
        Source<TabContents>(source).ptr()->property_bag());
  } else if (type == chrome::NOTIFICATION_HIDE_KEYBOARD_INVOKED) {
    UpdateKeyboardAndLayout(false);
  } else if (type == chrome::NOTIFICATION_SET_KEYBOARD_HEIGHT_INVOKED) {
    // TODO(penghuang) Allow extension conrtol the virtual keyboard directly
    // instead of using Notification.
    int height = *(Details<int>(details).ptr());
    if (height != keyboard_height_) {
      DCHECK_GE(height, 0) << "Height of the keyboard is less than 0.";
      DCHECK_LE(height, View::height()) << "Height of the keyboard is greater "
          "than the height of containing view.";
      keyboard_height_ = height;
      Layout();
    }
  }
}

// ui::AnimationDelegate implementation ----------------------------------------

void TouchLoginView::AnimationProgressed(const ui::Animation* anim) {
  ui::Transform transform;
  transform.SetTranslateY(
      ui::Tween::ValueBetween(anim->GetCurrentValue(), keyboard_height_, 0));
  keyboard_->SetTransform(transform);
}

void TouchLoginView::AnimationEnded(const ui::Animation* animation) {
  if (keyboard_showing_) {
    Layout();
  } else {
    // Notify the keyboard that it is hidden now.
    keyboard_->SetVisible(false);
  }
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/chromeos/login/webui_login_view.h"

#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/accessibility_util.h"
#include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/status/clock_menu_button.h"
#include "chrome/browser/chromeos/status/input_method_menu_button.h"
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/common/render_messages.h"
#include "content/browser/renderer_host/render_view_host_observer.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "views/widget/native_widget_gtk.h"
#include "views/widget/widget.h"

#if defined(TOUCH_UI)
#include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
#endif

namespace {

const char kViewClassName[] = "browser/chromeos/login/WebUILoginView";

// These strings must be kept in sync with handleAccelerator() in oobe.js.
const char kAccelNameAccessibility[] = "accessibility";
const char kAccelNameCancel[] = "cancel";
const char kAccelNameEnrollment[] = "enrollment";

// Observes IPC messages from the FrameSniffer and notifies JS if error
// appears.
class SnifferObserver : public RenderViewHostObserver {
 public:
  SnifferObserver(RenderViewHost* host, WebUI* webui)
      : RenderViewHostObserver(host), webui_(webui) {
    DCHECK(webui_);
    Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
                                             UTF8ToUTF16("gaia-frame")));
  }

  virtual ~SnifferObserver() {}

  // IPC::Channel::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SnifferObserver, message)
      IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnError)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

 private:
  void OnError(int error) {
    base::FundamentalValue error_value(error);
    webui_->CallJavascriptFunction("login.OfflineMessageScreen.onFrameError",
                                   error_value);
  }

  WebUI* webui_;
};

// A View class which places its first child at the right most position.
class RightAlignedView : public views::View {
 public:
  virtual void Layout() OVERRIDE;
  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
};

void RightAlignedView::Layout() {
  if (has_children()) {
    views::View* child = child_at(0);
    gfx::Size preferred_size = child->GetPreferredSize();
    child->SetBounds(width() - preferred_size.width(),
                     0, preferred_size.width(), preferred_size.height());
  }
}

void RightAlignedView::ChildPreferredSizeChanged(View* child) {
  Layout();
}

}  // namespace

namespace chromeos {

// static
const int WebUILoginView::kStatusAreaCornerPadding = 5;

// WebUILoginView public: ------------------------------------------------------

WebUILoginView::WebUILoginView()
    : status_area_(NULL),
      webui_login_(NULL),
      status_window_(NULL),
      host_window_frozen_(false),
      status_area_visibility_on_init_(true) {
#if defined(TOUCH_UI)
  // Make sure the singleton KeyboardManager object is created.
  KeyboardManager::GetInstance();
#endif
  accel_map_[views::Accelerator(ui::VKEY_Z, false, true, true)] =
      kAccelNameAccessibility;
  accel_map_[views::Accelerator(ui::VKEY_ESCAPE, false, false, false)] =
      kAccelNameCancel;
  accel_map_[views::Accelerator(ui::VKEY_E, false, true, true)] =
      kAccelNameEnrollment;

  for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
    AddAccelerator(i->first);
}

WebUILoginView::~WebUILoginView() {
  if (status_window_)
    status_window_->Close();
  status_window_ = NULL;
}

void WebUILoginView::Init() {

  webui_login_ = new DOMView();
  AddChildView(webui_login_);
  webui_login_->Init(ProfileManager::GetDefaultProfile(), NULL);
  webui_login_->SetVisible(true);
  webui_login_->tab_contents()->set_delegate(this);

  tab_watcher_.reset(new TabFirstRenderWatcher(webui_login_->tab_contents(),
                                               this));
}

std::string WebUILoginView::GetClassName() const {
  return kViewClassName;
}

bool WebUILoginView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  AccelMap::const_iterator entry = accel_map_.find(accelerator);
  if (entry == accel_map_.end())
    return false;

  if (!webui_login_)
    return true;

  WebUI* web_ui = webui_login_->tab_contents()->web_ui();
  if (web_ui) {
    base::StringValue accel_name(entry->second);
    web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
                                   accel_name);
  }

  return true;
}

gfx::NativeWindow WebUILoginView::GetNativeWindow() const {
  return GetWidget()->GetNativeWindow();
}

void WebUILoginView::OnWindowCreated() {
  // Freezes host window update until the tab is rendered.
  host_window_frozen_ = static_cast<views::NativeWidgetGtk*>(
      GetWidget()->native_widget())->SuppressFreezeUpdates();
}

void WebUILoginView::UpdateWindowType() {
  std::vector<int> params;
  WmIpc::instance()->SetWindowType(
      GTK_WIDGET(GetNativeWindow()),
      WM_IPC_WINDOW_LOGIN_WEBUI,
      &params);
}

void WebUILoginView::LoadURL(const GURL & url) {
  webui_login_->LoadURL(url);
  webui_login_->RequestFocus();
}

WebUI* WebUILoginView::GetWebUI() {
  return webui_login_->tab_contents()->web_ui();
}

void WebUILoginView::SetStatusAreaEnabled(bool enable) {
  if (status_area_)
    status_area_->MakeButtonsActive(enable);
}

void WebUILoginView::SetStatusAreaVisible(bool visible) {
  if (status_area_)
    status_area_->SetVisible(visible);
  else
    status_area_visibility_on_init_ = visible;
}

// WebUILoginView protected: ---------------------------------------------------

void WebUILoginView::Layout() {
  DCHECK(webui_login_);
  webui_login_->SetBoundsRect(bounds());
}

void WebUILoginView::ChildPreferredSizeChanged(View* child) {
  Layout();
  SchedulePaint();
}

Profile* WebUILoginView::GetProfile() const {
  return ProfileManager::GetDefaultProfile();
}

void WebUILoginView::ExecuteBrowserCommand(int id) const {
}

bool WebUILoginView::ShouldOpenButtonOptions(
    const views::View* button_view) const {
  if (button_view == status_area_->network_view())
    return true;

  if (button_view == status_area_->clock_view() ||
      button_view == status_area_->input_method_view())
    return false;

  return true;
}

void WebUILoginView::OpenButtonOptions(const views::View* button_view) {
  if (button_view == status_area_->network_view()) {
    if (proxy_settings_dialog_.get() == NULL) {
      proxy_settings_dialog_.reset(new ProxySettingsDialog(
          this, GetNativeWindow()));
    }
    proxy_settings_dialog_->Show();
  }
}

StatusAreaHost::ScreenMode WebUILoginView::GetScreenMode() const {
  return kWebUILoginMode;
}

StatusAreaHost::TextStyle WebUILoginView::GetTextStyle() const {
  return kGrayPlain;
}

void WebUILoginView::ButtonVisibilityChanged(views::View* button_view) {
  status_area_->ButtonVisibilityChanged(button_view);
}

void WebUILoginView::OnDialogClosed() {
}

void WebUILoginView::OnLocaleChanged() {
  // Proxy settings dialog contains localized strings.
  proxy_settings_dialog_.reset();
  SchedulePaint();
}

void WebUILoginView::OnRenderHostCreated(RenderViewHost* host) {
  new SnifferObserver(host, GetWebUI());
}

void WebUILoginView::OnTabMainFrameLoaded() {
}

void WebUILoginView::OnTabMainFrameFirstRender() {
  InitStatusArea();

  if (host_window_frozen_) {
    host_window_frozen_ = false;

    // Unfreezes the host window since tab is rendereed now.
    views::NativeWidgetGtk::UpdateFreezeUpdatesProperty(
        GetNativeWindow(), false);
  }
}

void WebUILoginView::InitStatusArea() {
  DCHECK(status_area_ == NULL);
  DCHECK(status_window_ == NULL);
  status_area_ = new StatusAreaView(this);
  status_area_->Init();
  status_area_->SetVisible(status_area_visibility_on_init_);

  views::Widget* login_window = WebUILoginDisplay::GetLoginWindow();
  // Width of |status_window| is meant to be large enough.
  // The current value of status_area_->GetPreferredSize().width()
  // will be too small when button status is changed.
  // (e.g. when CapsLock indicator appears)
  gfx::Size widget_size(width()/2,
                        status_area_->GetPreferredSize().height());
  const int widget_x = base::i18n::IsRTL() ?
      kStatusAreaCornerPadding :
      width() - widget_size.width() - kStatusAreaCornerPadding;
  gfx::Rect widget_bounds(widget_x, kStatusAreaCornerPadding,
                          widget_size.width(), widget_size.height());
  // TODO(nkostylev): Make status area in the same window as |webui_login_|
  // once RenderWidgetHostViewViews is ready.
#if defined(TOUCH_UI)
  // TODO(oshima): Window manager doesn't know about touch event, hence can't
  // activate the window. Use POPUP for now. This will be non issue
  // once we move to pure views + in chrome WM.
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_POPUP);
#else
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
#endif
  widget_params.bounds = widget_bounds;
  widget_params.transparent = true;
  widget_params.parent = login_window->GetNativeView();
  status_window_ = new views::Widget;
  status_window_->Init(widget_params);
  chromeos::WmIpc::instance()->SetWindowType(
      status_window_->GetNativeView(),
      chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
      NULL);
  views::View* contents_view = new RightAlignedView;
  contents_view->AddChildView(status_area_);
  status_window_->SetContentsView(contents_view);
  status_window_->Show();
}

// WebUILoginView private: -----------------------------------------------------

bool WebUILoginView::HandleContextMenu(const ContextMenuParams& params) {
  // Do not show the context menu.
#ifndef NDEBUG
  return false;
#else
  return true;
#endif
}

bool WebUILoginView::IsPopupOrPanel(const TabContents* source) const {
  return true;
}

bool WebUILoginView::TakeFocus(bool reverse) {
  // Forward the focus back to web contents.
  webui_login_->tab_contents()->FocusThroughTabTraversal(reverse);
  return true;
}

void WebUILoginView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
                                                        GetFocusManager());

  // Make sure error bubble is cleared on keyboard event. This is needed
  // when the focus is inside an iframe.
  WebUI* web_ui = GetWebUI();
  if (web_ui)
    web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
}

}  // namespace chromeos
<commit_msg>Another attempt to fix crash in clock menu button.<commit_after>// Copyright (c) 2011 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/chromeos/login/webui_login_view.h"

#include "base/i18n/rtl.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/accessibility_util.h"
#include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
#include "chrome/browser/chromeos/status/clock_menu_button.h"
#include "chrome/browser/chromeos/status/input_method_menu_button.h"
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_view.h"
#include "chrome/browser/chromeos/wm_ipc.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/common/render_messages.h"
#include "content/browser/renderer_host/render_view_host_observer.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "views/widget/native_widget_gtk.h"
#include "views/widget/widget.h"

#if defined(TOUCH_UI)
#include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
#endif

namespace {

const char kViewClassName[] = "browser/chromeos/login/WebUILoginView";

// These strings must be kept in sync with handleAccelerator() in oobe.js.
const char kAccelNameAccessibility[] = "accessibility";
const char kAccelNameCancel[] = "cancel";
const char kAccelNameEnrollment[] = "enrollment";

// Observes IPC messages from the FrameSniffer and notifies JS if error
// appears.
class SnifferObserver : public RenderViewHostObserver {
 public:
  SnifferObserver(RenderViewHost* host, WebUI* webui)
      : RenderViewHostObserver(host), webui_(webui) {
    DCHECK(webui_);
    Send(new ChromeViewMsg_StartFrameSniffer(routing_id(),
                                             UTF8ToUTF16("gaia-frame")));
  }

  virtual ~SnifferObserver() {}

  // IPC::Channel::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) {
    bool handled = true;
    IPC_BEGIN_MESSAGE_MAP(SnifferObserver, message)
      IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FrameLoadingError, OnError)
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP()
    return handled;
  }

 private:
  void OnError(int error) {
    base::FundamentalValue error_value(error);
    webui_->CallJavascriptFunction("login.OfflineMessageScreen.onFrameError",
                                   error_value);
  }

  WebUI* webui_;
};

// A View class which places its first child at the right most position.
class RightAlignedView : public views::View {
 public:
  virtual void Layout() OVERRIDE;
  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
};

void RightAlignedView::Layout() {
  if (has_children()) {
    views::View* child = child_at(0);
    gfx::Size preferred_size = child->GetPreferredSize();
    child->SetBounds(width() - preferred_size.width(),
                     0, preferred_size.width(), preferred_size.height());
  }
}

void RightAlignedView::ChildPreferredSizeChanged(View* child) {
  Layout();
}

}  // namespace

namespace chromeos {

// static
const int WebUILoginView::kStatusAreaCornerPadding = 5;

// WebUILoginView public: ------------------------------------------------------

WebUILoginView::WebUILoginView()
    : status_area_(NULL),
      webui_login_(NULL),
      status_window_(NULL),
      host_window_frozen_(false),
      status_area_visibility_on_init_(true) {
#if defined(TOUCH_UI)
  // Make sure the singleton KeyboardManager object is created.
  KeyboardManager::GetInstance();
#endif
  accel_map_[views::Accelerator(ui::VKEY_Z, false, true, true)] =
      kAccelNameAccessibility;
  accel_map_[views::Accelerator(ui::VKEY_ESCAPE, false, false, false)] =
      kAccelNameCancel;
  accel_map_[views::Accelerator(ui::VKEY_E, false, true, true)] =
      kAccelNameEnrollment;

  for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
    AddAccelerator(i->first);
}

WebUILoginView::~WebUILoginView() {
  if (status_window_)
    status_window_->CloseNow();
  status_window_ = NULL;
}

void WebUILoginView::Init() {

  webui_login_ = new DOMView();
  AddChildView(webui_login_);
  webui_login_->Init(ProfileManager::GetDefaultProfile(), NULL);
  webui_login_->SetVisible(true);
  webui_login_->tab_contents()->set_delegate(this);

  tab_watcher_.reset(new TabFirstRenderWatcher(webui_login_->tab_contents(),
                                               this));
}

std::string WebUILoginView::GetClassName() const {
  return kViewClassName;
}

bool WebUILoginView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  AccelMap::const_iterator entry = accel_map_.find(accelerator);
  if (entry == accel_map_.end())
    return false;

  if (!webui_login_)
    return true;

  WebUI* web_ui = webui_login_->tab_contents()->web_ui();
  if (web_ui) {
    base::StringValue accel_name(entry->second);
    web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
                                   accel_name);
  }

  return true;
}

gfx::NativeWindow WebUILoginView::GetNativeWindow() const {
  return GetWidget()->GetNativeWindow();
}

void WebUILoginView::OnWindowCreated() {
  // Freezes host window update until the tab is rendered.
  host_window_frozen_ = static_cast<views::NativeWidgetGtk*>(
      GetWidget()->native_widget())->SuppressFreezeUpdates();
}

void WebUILoginView::UpdateWindowType() {
  std::vector<int> params;
  WmIpc::instance()->SetWindowType(
      GTK_WIDGET(GetNativeWindow()),
      WM_IPC_WINDOW_LOGIN_WEBUI,
      &params);
}

void WebUILoginView::LoadURL(const GURL & url) {
  webui_login_->LoadURL(url);
  webui_login_->RequestFocus();
}

WebUI* WebUILoginView::GetWebUI() {
  return webui_login_->tab_contents()->web_ui();
}

void WebUILoginView::SetStatusAreaEnabled(bool enable) {
  if (status_area_)
    status_area_->MakeButtonsActive(enable);
}

void WebUILoginView::SetStatusAreaVisible(bool visible) {
  if (status_area_)
    status_area_->SetVisible(visible);
  else
    status_area_visibility_on_init_ = visible;
}

// WebUILoginView protected: ---------------------------------------------------

void WebUILoginView::Layout() {
  DCHECK(webui_login_);
  webui_login_->SetBoundsRect(bounds());
}

void WebUILoginView::ChildPreferredSizeChanged(View* child) {
  Layout();
  SchedulePaint();
}

Profile* WebUILoginView::GetProfile() const {
  return NULL;
}

void WebUILoginView::ExecuteBrowserCommand(int id) const {
}

bool WebUILoginView::ShouldOpenButtonOptions(
    const views::View* button_view) const {
  if (button_view == status_area_->network_view())
    return true;

  if (button_view == status_area_->clock_view() ||
      button_view == status_area_->input_method_view())
    return false;

  return true;
}

void WebUILoginView::OpenButtonOptions(const views::View* button_view) {
  if (button_view == status_area_->network_view()) {
    if (proxy_settings_dialog_.get() == NULL) {
      proxy_settings_dialog_.reset(new ProxySettingsDialog(
          this, GetNativeWindow()));
    }
    proxy_settings_dialog_->Show();
  }
}

StatusAreaHost::ScreenMode WebUILoginView::GetScreenMode() const {
  return kWebUILoginMode;
}

StatusAreaHost::TextStyle WebUILoginView::GetTextStyle() const {
  return kGrayPlain;
}

void WebUILoginView::ButtonVisibilityChanged(views::View* button_view) {
  status_area_->ButtonVisibilityChanged(button_view);
}

void WebUILoginView::OnDialogClosed() {
}

void WebUILoginView::OnLocaleChanged() {
  // Proxy settings dialog contains localized strings.
  proxy_settings_dialog_.reset();
  SchedulePaint();
}

void WebUILoginView::OnRenderHostCreated(RenderViewHost* host) {
  new SnifferObserver(host, GetWebUI());
}

void WebUILoginView::OnTabMainFrameLoaded() {
}

void WebUILoginView::OnTabMainFrameFirstRender() {
  InitStatusArea();

  if (host_window_frozen_) {
    host_window_frozen_ = false;

    // Unfreezes the host window since tab is rendereed now.
    views::NativeWidgetGtk::UpdateFreezeUpdatesProperty(
        GetNativeWindow(), false);
  }
}

void WebUILoginView::InitStatusArea() {
  DCHECK(status_area_ == NULL);
  DCHECK(status_window_ == NULL);
  status_area_ = new StatusAreaView(this);
  status_area_->Init();
  status_area_->SetVisible(status_area_visibility_on_init_);

  views::Widget* login_window = WebUILoginDisplay::GetLoginWindow();
  // Width of |status_window| is meant to be large enough.
  // The current value of status_area_->GetPreferredSize().width()
  // will be too small when button status is changed.
  // (e.g. when CapsLock indicator appears)
  gfx::Size widget_size(width()/2,
                        status_area_->GetPreferredSize().height());
  const int widget_x = base::i18n::IsRTL() ?
      kStatusAreaCornerPadding :
      width() - widget_size.width() - kStatusAreaCornerPadding;
  gfx::Rect widget_bounds(widget_x, kStatusAreaCornerPadding,
                          widget_size.width(), widget_size.height());
  // TODO(nkostylev): Make status area in the same window as |webui_login_|
  // once RenderWidgetHostViewViews is ready.
#if defined(TOUCH_UI)
  // TODO(oshima): Window manager doesn't know about touch event, hence can't
  // activate the window. Use POPUP for now. This will be non issue
  // once we move to pure views + in chrome WM.
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_POPUP);
#else
  views::Widget::InitParams widget_params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
#endif
  widget_params.bounds = widget_bounds;
  widget_params.transparent = true;
  widget_params.parent = login_window->GetNativeView();
  status_window_ = new views::Widget;
  status_window_->Init(widget_params);
  chromeos::WmIpc::instance()->SetWindowType(
      status_window_->GetNativeView(),
      chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
      NULL);
  views::View* contents_view = new RightAlignedView;
  contents_view->AddChildView(status_area_);
  status_window_->SetContentsView(contents_view);
  status_window_->Show();
}

// WebUILoginView private: -----------------------------------------------------

bool WebUILoginView::HandleContextMenu(const ContextMenuParams& params) {
  // Do not show the context menu.
#ifndef NDEBUG
  return false;
#else
  return true;
#endif
}

bool WebUILoginView::IsPopupOrPanel(const TabContents* source) const {
  return true;
}

bool WebUILoginView::TakeFocus(bool reverse) {
  // Forward the focus back to web contents.
  webui_login_->tab_contents()->FocusThroughTabTraversal(reverse);
  return true;
}

void WebUILoginView::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
                                                        GetFocusManager());

  // Make sure error bubble is cleared on keyboard event. This is needed
  // when the focus is inside an iframe.
  WebUI* web_ui = GetWebUI();
  if (web_ui)
    web_ui->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   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 Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <tdebug.h>

#include "id3v2framefactory.h"
#include "id3v2synchdata.h"
#include "id3v1genres.h"

#include "frames/attachedpictureframe.h"
#include "frames/commentsframe.h"
#include "frames/relativevolumeframe.h"
#include "frames/textidentificationframe.h"
#include "frames/uniquefileidentifierframe.h"
#include "frames/unknownframe.h"
#include "frames/generalencapsulatedobjectframe.h"
#include "frames/urllinkframe.h"
#include "frames/unsynchronizedlyricsframe.h"
#include "frames/popularimeterframe.h"
#include "frames/privateframe.h"

using namespace TagLib;
using namespace ID3v2;

class FrameFactory::FrameFactoryPrivate
{
public:
  FrameFactoryPrivate() :
    defaultEncoding(String::Latin1),
    useDefaultEncoding(false) {}

  String::Type defaultEncoding;
  bool useDefaultEncoding;

  template <class T> void setTextEncoding(T *frame)
  {
    if(useDefaultEncoding)
      frame->setTextEncoding(defaultEncoding);
  }
};

FrameFactory *FrameFactory::factory = 0;

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

FrameFactory *FrameFactory::instance()
{
  if(!factory)
    factory = new FrameFactory;
  return factory;
}

Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const
{
  return createFrame(data, uint(synchSafeInts ? 4 : 3));
}

Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const
{
  Header tagHeader;
  tagHeader.setMajorVersion(version);
  return createFrame(data, &tagHeader);
}

Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const
{
  ByteVector data = origData;
  uint version = tagHeader->majorVersion();
  Frame::Header *header = new Frame::Header(data, version);
  ByteVector frameID = header->frameID();

  // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1
  // characters.  Also make sure that there is data in the frame.

  if(!frameID.size() == (version < 3 ? 3 : 4) ||
     header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) ||
     header->frameSize() > data.size())
  {
    delete header;
    return 0;
  }

  for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
    if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
      delete header;
      return 0;
    }
  }

  if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) {
    // Data lengths are not part of the encoded data, but since they are synch-safe
    // integers they will be never actually encoded.
    ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize());
    frameData = SynchData::decode(frameData);
    data = data.mid(0, Frame::Header::size(version)) + frameData;
  }

  // TagLib doesn't mess with encrypted frames, so just treat them
  // as unknown frames.

#if HAVE_ZLIB == 0
  if(header->compression()) {
    debug("Compressed frames are currently not supported.");
    return new UnknownFrame(data, header);
  }
#endif
  if(header->encryption()) {
    debug("Encrypted frames are currently not supported.");
    return new UnknownFrame(data, header);
  }

  if(!updateFrame(header)) {
    header->setTagAlterPreservation(true);
    return new UnknownFrame(data, header);
  }

  // updateFrame() might have updated the frame ID.

  frameID = header->frameID();

  // This is where things get necissarily nasty.  Here we determine which
  // Frame subclass (or if none is found simply an Frame) based
  // on the frame ID.  Since there are a lot of possibilities, that means
  // a lot of if blocks.

  // Text Identification (frames 4.2)

  if(frameID.startsWith("T")) {

    TextIdentificationFrame *f = frameID != "TXXX"
      ? new TextIdentificationFrame(data, header)
      : new UserTextIdentificationFrame(data, header);

    d->setTextEncoding(f);

    if(frameID == "TCON")
      updateGenre(f);

    return f;
  }

  // Comments (frames 4.10)

  if(frameID == "COMM") {
    CommentsFrame *f = new CommentsFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // Attached Picture (frames 4.14)

  if(frameID == "APIC") {
    AttachedPictureFrame *f = new AttachedPictureFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // ID3v2.2 Attached Picture

  if(frameID == "PIC") {
    AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // Relative Volume Adjustment (frames 4.11)

  if(frameID == "RVA2")
    return new RelativeVolumeFrame(data, header);

  // Unique File Identifier (frames 4.1)

  if(frameID == "UFID")
    return new UniqueFileIdentifierFrame(data, header);

  // General Encapsulated Object (frames 4.15)

  if(frameID == "GEOB") {
    GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // URL link (frames 4.3)

  if(frameID.startsWith("W")) {
    if(frameID != "WXXX") {
      return new UrlLinkFrame(data, header);
    }
    else {
      UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header);
      d->setTextEncoding(f);
      return f;
    }
  }

  // Unsynchronized lyric/text transcription (frames 4.8)

  if(frameID == "USLT") {
    UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header);
    if(d->useDefaultEncoding)
      f->setTextEncoding(d->defaultEncoding);
    return f;
  }

  // Popularimeter (frames 4.17)

  if(frameID == "POPM")
    return new PopularimeterFrame(data, header);

  // Private (frames 4.27)

  if(frameID == "PRIV")
    return new PrivateFrame(data, header);

  return new UnknownFrame(data, header);
}

String::Type FrameFactory::defaultTextEncoding() const
{
  return d->defaultEncoding;
}

void FrameFactory::setDefaultTextEncoding(String::Type encoding)
{
  d->useDefaultEncoding = true;
  d->defaultEncoding = encoding;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

FrameFactory::FrameFactory()
{
  d = new FrameFactoryPrivate;
}

FrameFactory::~FrameFactory()
{
  delete d;
}

bool FrameFactory::updateFrame(Frame::Header *header) const
{
  TagLib::ByteVector frameID = header->frameID();

  switch(header->version()) {

  case 2: // ID3v2.2
  {
    if(frameID == "CRM" ||
       frameID == "EQU" ||
       frameID == "LNK" ||
       frameID == "RVA" ||
       frameID == "TIM" ||
       frameID == "TSI" ||
       frameID == "TDA")
    {
      debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
            ".  It will be discarded from the tag.");
      return false;
    }

    // ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
    // the frames to their 4 byte ID3v2.4 equivalent.

    convertFrame("BUF", "RBUF", header);
    convertFrame("CNT", "PCNT", header);
    convertFrame("COM", "COMM", header);
    convertFrame("CRA", "AENC", header);
    convertFrame("ETC", "ETCO", header);
    convertFrame("GEO", "GEOB", header);
    convertFrame("IPL", "TIPL", header);
    convertFrame("MCI", "MCDI", header);
    convertFrame("MLL", "MLLT", header);
    convertFrame("POP", "POPM", header);
    convertFrame("REV", "RVRB", header);
    convertFrame("SLT", "SYLT", header);
    convertFrame("STC", "SYTC", header);
    convertFrame("TAL", "TALB", header);
    convertFrame("TBP", "TBPM", header);
    convertFrame("TCM", "TCOM", header);
    convertFrame("TCO", "TCON", header);
    convertFrame("TCP", "TCMP", header);
    convertFrame("TCR", "TCOP", header);
    convertFrame("TDY", "TDLY", header);
    convertFrame("TEN", "TENC", header);
    convertFrame("TFT", "TFLT", header);
    convertFrame("TKE", "TKEY", header);
    convertFrame("TLA", "TLAN", header);
    convertFrame("TLE", "TLEN", header);
    convertFrame("TMT", "TMED", header);
    convertFrame("TOA", "TOAL", header);
    convertFrame("TOF", "TOFN", header);
    convertFrame("TOL", "TOLY", header);
    convertFrame("TOR", "TDOR", header);
    convertFrame("TOT", "TOAL", header);
    convertFrame("TP1", "TPE1", header);
    convertFrame("TP2", "TPE2", header);
    convertFrame("TP3", "TPE3", header);
    convertFrame("TP4", "TPE4", header);
    convertFrame("TPA", "TPOS", header);
    convertFrame("TPB", "TPUB", header);
    convertFrame("TRC", "TSRC", header);
    convertFrame("TRD", "TDRC", header);
    convertFrame("TRK", "TRCK", header);
    convertFrame("TS2", "TSO2", header);
    convertFrame("TSA", "TSOA", header);
    convertFrame("TSC", "TSOC", header);
    convertFrame("TSP", "TSOP", header);
    convertFrame("TSS", "TSSE", header);
    convertFrame("TST", "TSOT", header);
    convertFrame("TT1", "TIT1", header);
    convertFrame("TT2", "TIT2", header);
    convertFrame("TT3", "TIT3", header);
    convertFrame("TXT", "TOLY", header);
    convertFrame("TXX", "TXXX", header);
    convertFrame("TYE", "TDRC", header);
    convertFrame("UFI", "UFID", header);
    convertFrame("ULT", "USLT", header);
    convertFrame("WAF", "WOAF", header);
    convertFrame("WAR", "WOAR", header);
    convertFrame("WAS", "WOAS", header);
    convertFrame("WCM", "WCOM", header);
    convertFrame("WCP", "WCOP", header);
    convertFrame("WPB", "WPUB", header);
    convertFrame("WXX", "WXXX", header);

    break;
  }

  case 3: // ID3v2.3
  {
    if(frameID == "EQUA" ||
       frameID == "RVAD" ||
       frameID == "TIME" ||
       frameID == "TRDA" ||
       frameID == "TSIZ" ||
       frameID == "TDAT")
    {
      debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
            ".  It will be discarded from the tag.");
      return false;
    }

    convertFrame("TORY", "TDOR", header);
    convertFrame("TYER", "TDRC", header);
    convertFrame("IPLS", "TIPL", header);

    break;
  }

  default:

    // This should catch a typo that existed in TagLib up to and including
    // version 1.1 where TRDC was used for the year rather than TDRC.

    convertFrame("TRDC", "TDRC", header);
    break;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void FrameFactory::convertFrame(const char *from, const char *to,
                                Frame::Header *header) const
{
  if(header->frameID() != from)
    return;

  // debug("ID3v2.4 no longer supports the frame type " + String(from) + "  It has" +
  //       "been converted to the type " + String(to) + ".");

  header->setFrameID(to);
}

void FrameFactory::updateGenre(TextIdentificationFrame *frame) const
{
  StringList fields = frame->fieldList();
  StringList newfields;

  for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) {
    String s = *it;
    int end = s.find(")");

    if(s.startsWith("(") && end > 0) {
      // "(12)Genre"
      String text = s.substr(end + 1);
      bool ok;
      int number = s.substr(1, end - 1).toInt(&ok);
      if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text))
        newfields.append(s.substr(1, end - 1));
      if(!text.isEmpty())
        newfields.append(text);
    }
    else {
      // "Genre" or "12"
      newfields.append(s);
    }
  }

  if(newfields.isEmpty())
    fields.append(String::null);

  frame->setText(newfields);

}
<commit_msg>Fixed memory leak of FrameFactory singleton.<commit_after>/***************************************************************************
    copyright            : (C) 2002 - 2008 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   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 Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <tdebug.h>

#include "id3v2framefactory.h"
#include "id3v2synchdata.h"
#include "id3v1genres.h"

#include "frames/attachedpictureframe.h"
#include "frames/commentsframe.h"
#include "frames/relativevolumeframe.h"
#include "frames/textidentificationframe.h"
#include "frames/uniquefileidentifierframe.h"
#include "frames/unknownframe.h"
#include "frames/generalencapsulatedobjectframe.h"
#include "frames/urllinkframe.h"
#include "frames/unsynchronizedlyricsframe.h"
#include "frames/popularimeterframe.h"
#include "frames/privateframe.h"

using namespace TagLib;
using namespace ID3v2;

class FrameFactory::FrameFactoryPrivate
{
public:
  FrameFactoryPrivate() :
    defaultEncoding(String::Latin1),
    useDefaultEncoding(false) {}

  String::Type defaultEncoding;
  bool useDefaultEncoding;

  template <class T> void setTextEncoding(T *frame)
  {
    if(useDefaultEncoding)
      frame->setTextEncoding(defaultEncoding);
  }
};

FrameFactory *FrameFactory::factory = 0;

////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////

FrameFactory *FrameFactory::instance()
{
  static FrameFactory factory;
  return &factory;
}

Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const
{
  return createFrame(data, uint(synchSafeInts ? 4 : 3));
}

Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const
{
  Header tagHeader;
  tagHeader.setMajorVersion(version);
  return createFrame(data, &tagHeader);
}

Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const
{
  ByteVector data = origData;
  uint version = tagHeader->majorVersion();
  Frame::Header *header = new Frame::Header(data, version);
  ByteVector frameID = header->frameID();

  // A quick sanity check -- make sure that the frameID is 4 uppercase Latin1
  // characters.  Also make sure that there is data in the frame.

  if(!frameID.size() == (version < 3 ? 3 : 4) ||
     header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) ||
     header->frameSize() > data.size())
  {
    delete header;
    return 0;
  }

  for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
    if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
      delete header;
      return 0;
    }
  }

  if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) {
    // Data lengths are not part of the encoded data, but since they are synch-safe
    // integers they will be never actually encoded.
    ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize());
    frameData = SynchData::decode(frameData);
    data = data.mid(0, Frame::Header::size(version)) + frameData;
  }

  // TagLib doesn't mess with encrypted frames, so just treat them
  // as unknown frames.

#if HAVE_ZLIB == 0
  if(header->compression()) {
    debug("Compressed frames are currently not supported.");
    return new UnknownFrame(data, header);
  }
#endif
  if(header->encryption()) {
    debug("Encrypted frames are currently not supported.");
    return new UnknownFrame(data, header);
  }

  if(!updateFrame(header)) {
    header->setTagAlterPreservation(true);
    return new UnknownFrame(data, header);
  }

  // updateFrame() might have updated the frame ID.

  frameID = header->frameID();

  // This is where things get necissarily nasty.  Here we determine which
  // Frame subclass (or if none is found simply an Frame) based
  // on the frame ID.  Since there are a lot of possibilities, that means
  // a lot of if blocks.

  // Text Identification (frames 4.2)

  if(frameID.startsWith("T")) {

    TextIdentificationFrame *f = frameID != "TXXX"
      ? new TextIdentificationFrame(data, header)
      : new UserTextIdentificationFrame(data, header);

    d->setTextEncoding(f);

    if(frameID == "TCON")
      updateGenre(f);

    return f;
  }

  // Comments (frames 4.10)

  if(frameID == "COMM") {
    CommentsFrame *f = new CommentsFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // Attached Picture (frames 4.14)

  if(frameID == "APIC") {
    AttachedPictureFrame *f = new AttachedPictureFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // ID3v2.2 Attached Picture

  if(frameID == "PIC") {
    AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // Relative Volume Adjustment (frames 4.11)

  if(frameID == "RVA2")
    return new RelativeVolumeFrame(data, header);

  // Unique File Identifier (frames 4.1)

  if(frameID == "UFID")
    return new UniqueFileIdentifierFrame(data, header);

  // General Encapsulated Object (frames 4.15)

  if(frameID == "GEOB") {
    GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header);
    d->setTextEncoding(f);
    return f;
  }

  // URL link (frames 4.3)

  if(frameID.startsWith("W")) {
    if(frameID != "WXXX") {
      return new UrlLinkFrame(data, header);
    }
    else {
      UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header);
      d->setTextEncoding(f);
      return f;
    }
  }

  // Unsynchronized lyric/text transcription (frames 4.8)

  if(frameID == "USLT") {
    UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header);
    if(d->useDefaultEncoding)
      f->setTextEncoding(d->defaultEncoding);
    return f;
  }

  // Popularimeter (frames 4.17)

  if(frameID == "POPM")
    return new PopularimeterFrame(data, header);

  // Private (frames 4.27)

  if(frameID == "PRIV")
    return new PrivateFrame(data, header);

  return new UnknownFrame(data, header);
}

String::Type FrameFactory::defaultTextEncoding() const
{
  return d->defaultEncoding;
}

void FrameFactory::setDefaultTextEncoding(String::Type encoding)
{
  d->useDefaultEncoding = true;
  d->defaultEncoding = encoding;
}

////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////

FrameFactory::FrameFactory()
{
  d = new FrameFactoryPrivate;
}

FrameFactory::~FrameFactory()
{
  delete d;
}

bool FrameFactory::updateFrame(Frame::Header *header) const
{
  TagLib::ByteVector frameID = header->frameID();

  switch(header->version()) {

  case 2: // ID3v2.2
  {
    if(frameID == "CRM" ||
       frameID == "EQU" ||
       frameID == "LNK" ||
       frameID == "RVA" ||
       frameID == "TIM" ||
       frameID == "TSI" ||
       frameID == "TDA")
    {
      debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
            ".  It will be discarded from the tag.");
      return false;
    }

    // ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of
    // the frames to their 4 byte ID3v2.4 equivalent.

    convertFrame("BUF", "RBUF", header);
    convertFrame("CNT", "PCNT", header);
    convertFrame("COM", "COMM", header);
    convertFrame("CRA", "AENC", header);
    convertFrame("ETC", "ETCO", header);
    convertFrame("GEO", "GEOB", header);
    convertFrame("IPL", "TIPL", header);
    convertFrame("MCI", "MCDI", header);
    convertFrame("MLL", "MLLT", header);
    convertFrame("POP", "POPM", header);
    convertFrame("REV", "RVRB", header);
    convertFrame("SLT", "SYLT", header);
    convertFrame("STC", "SYTC", header);
    convertFrame("TAL", "TALB", header);
    convertFrame("TBP", "TBPM", header);
    convertFrame("TCM", "TCOM", header);
    convertFrame("TCO", "TCON", header);
    convertFrame("TCP", "TCMP", header);
    convertFrame("TCR", "TCOP", header);
    convertFrame("TDY", "TDLY", header);
    convertFrame("TEN", "TENC", header);
    convertFrame("TFT", "TFLT", header);
    convertFrame("TKE", "TKEY", header);
    convertFrame("TLA", "TLAN", header);
    convertFrame("TLE", "TLEN", header);
    convertFrame("TMT", "TMED", header);
    convertFrame("TOA", "TOAL", header);
    convertFrame("TOF", "TOFN", header);
    convertFrame("TOL", "TOLY", header);
    convertFrame("TOR", "TDOR", header);
    convertFrame("TOT", "TOAL", header);
    convertFrame("TP1", "TPE1", header);
    convertFrame("TP2", "TPE2", header);
    convertFrame("TP3", "TPE3", header);
    convertFrame("TP4", "TPE4", header);
    convertFrame("TPA", "TPOS", header);
    convertFrame("TPB", "TPUB", header);
    convertFrame("TRC", "TSRC", header);
    convertFrame("TRD", "TDRC", header);
    convertFrame("TRK", "TRCK", header);
    convertFrame("TS2", "TSO2", header);
    convertFrame("TSA", "TSOA", header);
    convertFrame("TSC", "TSOC", header);
    convertFrame("TSP", "TSOP", header);
    convertFrame("TSS", "TSSE", header);
    convertFrame("TST", "TSOT", header);
    convertFrame("TT1", "TIT1", header);
    convertFrame("TT2", "TIT2", header);
    convertFrame("TT3", "TIT3", header);
    convertFrame("TXT", "TOLY", header);
    convertFrame("TXX", "TXXX", header);
    convertFrame("TYE", "TDRC", header);
    convertFrame("UFI", "UFID", header);
    convertFrame("ULT", "USLT", header);
    convertFrame("WAF", "WOAF", header);
    convertFrame("WAR", "WOAR", header);
    convertFrame("WAS", "WOAS", header);
    convertFrame("WCM", "WCOM", header);
    convertFrame("WCP", "WCOP", header);
    convertFrame("WPB", "WPUB", header);
    convertFrame("WXX", "WXXX", header);

    break;
  }

  case 3: // ID3v2.3
  {
    if(frameID == "EQUA" ||
       frameID == "RVAD" ||
       frameID == "TIME" ||
       frameID == "TRDA" ||
       frameID == "TSIZ" ||
       frameID == "TDAT")
    {
      debug("ID3v2.4 no longer supports the frame type " + String(frameID) +
            ".  It will be discarded from the tag.");
      return false;
    }

    convertFrame("TORY", "TDOR", header);
    convertFrame("TYER", "TDRC", header);
    convertFrame("IPLS", "TIPL", header);

    break;
  }

  default:

    // This should catch a typo that existed in TagLib up to and including
    // version 1.1 where TRDC was used for the year rather than TDRC.

    convertFrame("TRDC", "TDRC", header);
    break;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

void FrameFactory::convertFrame(const char *from, const char *to,
                                Frame::Header *header) const
{
  if(header->frameID() != from)
    return;

  // debug("ID3v2.4 no longer supports the frame type " + String(from) + "  It has" +
  //       "been converted to the type " + String(to) + ".");

  header->setFrameID(to);
}

void FrameFactory::updateGenre(TextIdentificationFrame *frame) const
{
  StringList fields = frame->fieldList();
  StringList newfields;

  for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) {
    String s = *it;
    int end = s.find(")");

    if(s.startsWith("(") && end > 0) {
      // "(12)Genre"
      String text = s.substr(end + 1);
      bool ok;
      int number = s.substr(1, end - 1).toInt(&ok);
      if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text))
        newfields.append(s.substr(1, end - 1));
      if(!text.isEmpty())
        newfields.append(text);
    }
    else {
      // "Genre" or "12"
      newfields.append(s);
    }
  }

  if(newfields.isEmpty())
    fields.append(String::null);

  frame->setText(newfields);

}
<|endoftext|>