<commit_before>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
 */

#include "config.h"
#include "platform/graphics/DeferredImageDecoder.h"

#include "platform/graphics/DecodingImageGenerator.h"
#include "platform/graphics/ImageDecodingStore.h"
#include "platform/graphics/LazyDecodingPixelRef.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "wtf/PassOwnPtr.h"

namespace WebCore {

namespace {

// URI label for a lazily decoded SkPixelRef.
const char labelLazyDecoded[] = "lazy";

// URI label for SkDiscardablePixelRef.
const char labelDiscardable[] = "discardable";

} // namespace

bool DeferredImageDecoder::s_enabled = false;
bool DeferredImageDecoder::s_skiaDiscardableMemoryEnabled = false;

DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder)
    : m_allDataReceived(false)
    , m_lastDataSize(0)
    , m_dataChanged(false)
    , m_actualDecoder(actualDecoder)
    , m_orientation(DefaultImageOrientation)
    , m_repetitionCount(cAnimationNone)
    , m_hasColorProfile(false)
{
}

DeferredImageDecoder::~DeferredImageDecoder()
{
}

PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorOption)
{
    OwnPtr<ImageDecoder> actualDecoder = ImageDecoder::create(data, alphaOption, gammaAndColorOption);
    return actualDecoder ? adoptPtr(new DeferredImageDecoder(actualDecoder.release())) : nullptr;
}

PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::createForTesting(PassOwnPtr<ImageDecoder> decoder)
{
    return adoptPtr(new DeferredImageDecoder(decoder));
}

bool DeferredImageDecoder::isLazyDecoded(const SkBitmap& bitmap)
{
    return bitmap.pixelRef()
        && bitmap.pixelRef()->getURI()
        && (!memcmp(bitmap.pixelRef()->getURI(), labelLazyDecoded, sizeof(labelLazyDecoded))
            || !memcmp(bitmap.pixelRef()->getURI(), labelDiscardable, sizeof(labelDiscardable)));
}

void DeferredImageDecoder::setEnabled(bool enabled)
{
    s_enabled = enabled;
    // FIXME: Remove all non-discardable memory related code now that this is
    // used on all platforms.
    s_skiaDiscardableMemoryEnabled = enabled;
    if (enabled)
        ImageDecodingStore::setImageCachingEnabled(false);
}

bool DeferredImageDecoder::enabled()
{
    return s_enabled;
}

String DeferredImageDecoder::filenameExtension() const
{
    return m_actualDecoder ? m_actualDecoder->filenameExtension() : m_filenameExtension;
}

ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index)
{
    prepareLazyDecodedFrames();
    if (index < m_lazyDecodedFrames.size()) {
        // ImageFrameGenerator has the latest known alpha state. There will
        // be a performance boost if this frame is opaque.
        m_lazyDecodedFrames[index]->setHasAlpha(m_frameGenerator->hasAlpha(index));
        return m_lazyDecodedFrames[index].get();
    }
    if (m_actualDecoder)
        return m_actualDecoder->frameBufferAtIndex(index);
    return 0;
}

void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived)
{
    if (m_actualDecoder) {
        const bool firstData = !m_data;
        const bool moreData = data.size() > m_lastDataSize;
        m_dataChanged = firstData || moreData;
        m_data = RefPtr<SharedBuffer>(data);
        m_lastDataSize = data.size();
        m_allDataReceived = allDataReceived;
        m_actualDecoder->setData(&data, allDataReceived);
        prepareLazyDecodedFrames();
    }

    if (m_frameGenerator)
        m_frameGenerator->setData(&data, allDataReceived);
}

bool DeferredImageDecoder::isSizeAvailable()
{
    // m_actualDecoder is 0 only if image decoding is deferred and that
    // means image header decoded successfully and size is available.
    return m_actualDecoder ? m_actualDecoder->isSizeAvailable() : true;
}

bool DeferredImageDecoder::hasColorProfile() const
{
    return m_actualDecoder ? m_actualDecoder->hasColorProfile() : m_hasColorProfile;
}

IntSize DeferredImageDecoder::size() const
{
    return m_actualDecoder ? m_actualDecoder->size() : m_size;
}

IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const
{
    // FIXME: LocalFrame size is assumed to be uniform. This might not be true for
    // future supported codecs.
    return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size;
}

size_t DeferredImageDecoder::frameCount()
{
    return m_actualDecoder ? m_actualDecoder->frameCount() : m_lazyDecodedFrames.size();
}

int DeferredImageDecoder::repetitionCount() const
{
    return m_actualDecoder ? m_actualDecoder->repetitionCount() : m_repetitionCount;
}

size_t DeferredImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
{
    // If image decoding is deferred then frame buffer cache is managed by
    // the compositor and this call is ignored.
    return m_actualDecoder ? m_actualDecoder->clearCacheExceptFrame(clearExceptFrame) : 0;
}

bool DeferredImageDecoder::frameHasAlphaAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameHasAlphaAtIndex(index);
    if (!m_frameGenerator->isMultiFrame())
        return m_frameGenerator->hasAlpha(index);
    return true;
}

bool DeferredImageDecoder::frameIsCompleteAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameIsCompleteAtIndex(index);
    if (index < m_lazyDecodedFrames.size())
        return m_lazyDecodedFrames[index]->status() == ImageFrame::FrameComplete;
    return false;
}

float DeferredImageDecoder::frameDurationAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameDurationAtIndex(index);
    if (index < m_lazyDecodedFrames.size())
        return m_lazyDecodedFrames[index]->duration();
    return 0;
}

unsigned DeferredImageDecoder::frameBytesAtIndex(size_t index) const
{
    // If frame decoding is deferred then it is not managed by MemoryCache
    // so return 0 here.
    return m_frameGenerator ? 0 : m_actualDecoder->frameBytesAtIndex(index);
}

ImageOrientation DeferredImageDecoder::orientation() const
{
    return m_actualDecoder ? m_actualDecoder->orientation() : m_orientation;
}

void DeferredImageDecoder::activateLazyDecoding()
{
    if (m_frameGenerator)
        return;
    m_size = m_actualDecoder->size();
    m_orientation = m_actualDecoder->orientation();
    m_filenameExtension = m_actualDecoder->filenameExtension();
    m_hasColorProfile = m_actualDecoder->hasColorProfile();
    const bool isSingleFrame = m_actualDecoder->repetitionCount() == cAnimationNone || (m_allDataReceived && m_actualDecoder->frameCount() == 1u);
    m_frameGenerator = ImageFrameGenerator::create(SkISize::Make(m_actualDecoder->decodedSize().width(), m_actualDecoder->decodedSize().height()), m_data, m_allDataReceived, !isSingleFrame);
}

void DeferredImageDecoder::prepareLazyDecodedFrames()
{
    if (!s_enabled
        || !m_actualDecoder
        || !m_actualDecoder->isSizeAvailable()
        || m_actualDecoder->filenameExtension() == "ico")
        return;

    activateLazyDecoding();

    const size_t previousSize = m_lazyDecodedFrames.size();
    m_lazyDecodedFrames.resize(m_actualDecoder->frameCount());

    // We have encountered a broken image file. Simply bail.
    if (m_lazyDecodedFrames.size() < previousSize)
        return;

    for (size_t i = previousSize; i < m_lazyDecodedFrames.size(); ++i) {
        OwnPtr<ImageFrame> frame(adoptPtr(new ImageFrame()));
        frame->setSkBitmap(createBitmap(i));
        frame->setDuration(m_actualDecoder->frameDurationAtIndex(i));
        frame->setStatus(m_actualDecoder->frameIsCompleteAtIndex(i) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
        m_lazyDecodedFrames[i] = frame.release();
    }

    // The last lazy decoded frame created from previous call might be
    // incomplete so update its state.
    if (previousSize) {
        const size_t lastFrame = previousSize - 1;
        m_lazyDecodedFrames[lastFrame]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(lastFrame) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);

        // If data has changed then create a new bitmap. This forces
        // Skia to decode again.
        if (m_dataChanged) {
            m_dataChanged = false;
            m_lazyDecodedFrames[lastFrame]->setSkBitmap(createBitmap(lastFrame));
        }
    }

    if (m_allDataReceived) {
        m_repetitionCount = m_actualDecoder->repetitionCount();
        m_actualDecoder.clear();
        m_data = nullptr;
    }
}

// Creates either a SkBitmap backed by SkDiscardablePixelRef or a SkBitmap using the
// legacy LazyDecodingPixelRef.
SkBitmap DeferredImageDecoder::createBitmap(size_t index)
{
    // This code is temporary until the transition to SkDiscardablePixelRef is complete.
    if (s_skiaDiscardableMemoryEnabled)
        return createSkiaDiscardableBitmap(index);
    return createLazyDecodingBitmap(index);
}

// Creates a SkBitmap that is backed by SkDiscardablePixelRef.
SkBitmap DeferredImageDecoder::createSkiaDiscardableBitmap(size_t index)
{
    IntSize decodedSize = m_actualDecoder->decodedSize();
    ASSERT(decodedSize.width() > 0);
    ASSERT(decodedSize.height() > 0);

    SkImageInfo info;
    info.fWidth = decodedSize.width();
    info.fHeight = decodedSize.height();
    info.fColorType = kBGRA_8888_SkColorType;
    info.fAlphaType = kPremul_SkAlphaType;

    SkBitmap bitmap;
    DecodingImageGenerator* generator = new DecodingImageGenerator(m_frameGenerator, info, index);
    bool installed = SkInstallDiscardablePixelRef(generator, &bitmap);
    ASSERT_UNUSED(installed, installed);
    bitmap.pixelRef()->setURI(labelDiscardable);
    generator->setGenerationId(bitmap.getGenerationID());
    return bitmap;
}

SkBitmap DeferredImageDecoder::createLazyDecodingBitmap(size_t index)
{
    IntSize decodedSize = m_actualDecoder->decodedSize();
    ASSERT(decodedSize.width() > 0);
    ASSERT(decodedSize.height() > 0);

    SkImageInfo info;
    info.fWidth = decodedSize.width();
    info.fHeight = decodedSize.height();
    info.fColorType = kPMColor_SkColorType;
    info.fAlphaType = kPremul_SkAlphaType;

    // Creates a lazily decoded SkPixelRef that references the entire image without scaling.
    SkBitmap bitmap;
    bitmap.setConfig(info);
    bitmap.setPixelRef(new LazyDecodingPixelRef(info, m_frameGenerator, index))->unref();

    // Use the URI to identify this as a lazily decoded SkPixelRef of type LazyDecodingPixelRef.
    // FIXME: It would be more useful to give the actual image URI.
    bitmap.pixelRef()->setURI(labelLazyDecoded);

    // Inform the bitmap that we will never change the pixels. This is a performance hint
    // subsystems that may try to cache this bitmap (e.g. pictures, pipes, gpu, pdf, etc.)
    bitmap.setImmutable();

    return bitmap;
}

bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const
{
    // TODO: Implement.
    return m_actualDecoder ? m_actualDecoder->hotSpot(hotSpot) : false;
}

} // namespace WebCore
<commit_msg>Revert 173540 "Use skia discardable memory for decoded images on..."<commit_after>/*
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
 */

#include "config.h"
#include "platform/graphics/DeferredImageDecoder.h"

#include "platform/graphics/DecodingImageGenerator.h"
#include "platform/graphics/ImageDecodingStore.h"
#include "platform/graphics/LazyDecodingPixelRef.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "wtf/PassOwnPtr.h"

namespace WebCore {

namespace {

// URI label for a lazily decoded SkPixelRef.
const char labelLazyDecoded[] = "lazy";

// URI label for SkDiscardablePixelRef.
const char labelDiscardable[] = "discardable";

} // namespace

bool DeferredImageDecoder::s_enabled = false;
bool DeferredImageDecoder::s_skiaDiscardableMemoryEnabled = false;

DeferredImageDecoder::DeferredImageDecoder(PassOwnPtr<ImageDecoder> actualDecoder)
    : m_allDataReceived(false)
    , m_lastDataSize(0)
    , m_dataChanged(false)
    , m_actualDecoder(actualDecoder)
    , m_orientation(DefaultImageOrientation)
    , m_repetitionCount(cAnimationNone)
    , m_hasColorProfile(false)
{
}

DeferredImageDecoder::~DeferredImageDecoder()
{
}

PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorOption)
{
    OwnPtr<ImageDecoder> actualDecoder = ImageDecoder::create(data, alphaOption, gammaAndColorOption);
    return actualDecoder ? adoptPtr(new DeferredImageDecoder(actualDecoder.release())) : nullptr;
}

PassOwnPtr<DeferredImageDecoder> DeferredImageDecoder::createForTesting(PassOwnPtr<ImageDecoder> decoder)
{
    return adoptPtr(new DeferredImageDecoder(decoder));
}

bool DeferredImageDecoder::isLazyDecoded(const SkBitmap& bitmap)
{
    return bitmap.pixelRef()
        && bitmap.pixelRef()->getURI()
        && (!memcmp(bitmap.pixelRef()->getURI(), labelLazyDecoded, sizeof(labelLazyDecoded))
            || !memcmp(bitmap.pixelRef()->getURI(), labelDiscardable, sizeof(labelDiscardable)));
}

void DeferredImageDecoder::setEnabled(bool enabled)
{
    s_enabled = enabled;
#if !OS(ANDROID)
    // FIXME: This code is temporary to enable discardable memory for
    // non-Android platforms. In the future all platforms will be
    // the same and we can remove this code.
    s_skiaDiscardableMemoryEnabled = enabled;
    if (enabled)
        ImageDecodingStore::setImageCachingEnabled(false);
#endif
}

bool DeferredImageDecoder::enabled()
{
    return s_enabled;
}

String DeferredImageDecoder::filenameExtension() const
{
    return m_actualDecoder ? m_actualDecoder->filenameExtension() : m_filenameExtension;
}

ImageFrame* DeferredImageDecoder::frameBufferAtIndex(size_t index)
{
    prepareLazyDecodedFrames();
    if (index < m_lazyDecodedFrames.size()) {
        // ImageFrameGenerator has the latest known alpha state. There will
        // be a performance boost if this frame is opaque.
        m_lazyDecodedFrames[index]->setHasAlpha(m_frameGenerator->hasAlpha(index));
        return m_lazyDecodedFrames[index].get();
    }
    if (m_actualDecoder)
        return m_actualDecoder->frameBufferAtIndex(index);
    return 0;
}

void DeferredImageDecoder::setData(SharedBuffer& data, bool allDataReceived)
{
    if (m_actualDecoder) {
        const bool firstData = !m_data;
        const bool moreData = data.size() > m_lastDataSize;
        m_dataChanged = firstData || moreData;
        m_data = RefPtr<SharedBuffer>(data);
        m_lastDataSize = data.size();
        m_allDataReceived = allDataReceived;
        m_actualDecoder->setData(&data, allDataReceived);
        prepareLazyDecodedFrames();
    }

    if (m_frameGenerator)
        m_frameGenerator->setData(&data, allDataReceived);
}

bool DeferredImageDecoder::isSizeAvailable()
{
    // m_actualDecoder is 0 only if image decoding is deferred and that
    // means image header decoded successfully and size is available.
    return m_actualDecoder ? m_actualDecoder->isSizeAvailable() : true;
}

bool DeferredImageDecoder::hasColorProfile() const
{
    return m_actualDecoder ? m_actualDecoder->hasColorProfile() : m_hasColorProfile;
}

IntSize DeferredImageDecoder::size() const
{
    return m_actualDecoder ? m_actualDecoder->size() : m_size;
}

IntSize DeferredImageDecoder::frameSizeAtIndex(size_t index) const
{
    // FIXME: LocalFrame size is assumed to be uniform. This might not be true for
    // future supported codecs.
    return m_actualDecoder ? m_actualDecoder->frameSizeAtIndex(index) : m_size;
}

size_t DeferredImageDecoder::frameCount()
{
    return m_actualDecoder ? m_actualDecoder->frameCount() : m_lazyDecodedFrames.size();
}

int DeferredImageDecoder::repetitionCount() const
{
    return m_actualDecoder ? m_actualDecoder->repetitionCount() : m_repetitionCount;
}

size_t DeferredImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame)
{
    // If image decoding is deferred then frame buffer cache is managed by
    // the compositor and this call is ignored.
    return m_actualDecoder ? m_actualDecoder->clearCacheExceptFrame(clearExceptFrame) : 0;
}

bool DeferredImageDecoder::frameHasAlphaAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameHasAlphaAtIndex(index);
    if (!m_frameGenerator->isMultiFrame())
        return m_frameGenerator->hasAlpha(index);
    return true;
}

bool DeferredImageDecoder::frameIsCompleteAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameIsCompleteAtIndex(index);
    if (index < m_lazyDecodedFrames.size())
        return m_lazyDecodedFrames[index]->status() == ImageFrame::FrameComplete;
    return false;
}

float DeferredImageDecoder::frameDurationAtIndex(size_t index) const
{
    if (m_actualDecoder)
        return m_actualDecoder->frameDurationAtIndex(index);
    if (index < m_lazyDecodedFrames.size())
        return m_lazyDecodedFrames[index]->duration();
    return 0;
}

unsigned DeferredImageDecoder::frameBytesAtIndex(size_t index) const
{
    // If frame decoding is deferred then it is not managed by MemoryCache
    // so return 0 here.
    return m_frameGenerator ? 0 : m_actualDecoder->frameBytesAtIndex(index);
}

ImageOrientation DeferredImageDecoder::orientation() const
{
    return m_actualDecoder ? m_actualDecoder->orientation() : m_orientation;
}

void DeferredImageDecoder::activateLazyDecoding()
{
    if (m_frameGenerator)
        return;
    m_size = m_actualDecoder->size();
    m_orientation = m_actualDecoder->orientation();
    m_filenameExtension = m_actualDecoder->filenameExtension();
    m_hasColorProfile = m_actualDecoder->hasColorProfile();
    const bool isSingleFrame = m_actualDecoder->repetitionCount() == cAnimationNone || (m_allDataReceived && m_actualDecoder->frameCount() == 1u);
    m_frameGenerator = ImageFrameGenerator::create(SkISize::Make(m_actualDecoder->decodedSize().width(), m_actualDecoder->decodedSize().height()), m_data, m_allDataReceived, !isSingleFrame);
}

void DeferredImageDecoder::prepareLazyDecodedFrames()
{
    if (!s_enabled
        || !m_actualDecoder
        || !m_actualDecoder->isSizeAvailable()
        || m_actualDecoder->filenameExtension() == "ico")
        return;

    activateLazyDecoding();

    const size_t previousSize = m_lazyDecodedFrames.size();
    m_lazyDecodedFrames.resize(m_actualDecoder->frameCount());

    // We have encountered a broken image file. Simply bail.
    if (m_lazyDecodedFrames.size() < previousSize)
        return;

    for (size_t i = previousSize; i < m_lazyDecodedFrames.size(); ++i) {
        OwnPtr<ImageFrame> frame(adoptPtr(new ImageFrame()));
        frame->setSkBitmap(createBitmap(i));
        frame->setDuration(m_actualDecoder->frameDurationAtIndex(i));
        frame->setStatus(m_actualDecoder->frameIsCompleteAtIndex(i) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);
        m_lazyDecodedFrames[i] = frame.release();
    }

    // The last lazy decoded frame created from previous call might be
    // incomplete so update its state.
    if (previousSize) {
        const size_t lastFrame = previousSize - 1;
        m_lazyDecodedFrames[lastFrame]->setStatus(m_actualDecoder->frameIsCompleteAtIndex(lastFrame) ? ImageFrame::FrameComplete : ImageFrame::FramePartial);

        // If data has changed then create a new bitmap. This forces
        // Skia to decode again.
        if (m_dataChanged) {
            m_dataChanged = false;
            m_lazyDecodedFrames[lastFrame]->setSkBitmap(createBitmap(lastFrame));
        }
    }

    if (m_allDataReceived) {
        m_repetitionCount = m_actualDecoder->repetitionCount();
        m_actualDecoder.clear();
        m_data = nullptr;
    }
}

// Creates either a SkBitmap backed by SkDiscardablePixelRef or a SkBitmap using the
// legacy LazyDecodingPixelRef.
SkBitmap DeferredImageDecoder::createBitmap(size_t index)
{
    // This code is temporary until the transition to SkDiscardablePixelRef is complete.
    if (s_skiaDiscardableMemoryEnabled)
        return createSkiaDiscardableBitmap(index);
    return createLazyDecodingBitmap(index);
}

// Creates a SkBitmap that is backed by SkDiscardablePixelRef.
SkBitmap DeferredImageDecoder::createSkiaDiscardableBitmap(size_t index)
{
    IntSize decodedSize = m_actualDecoder->decodedSize();
    ASSERT(decodedSize.width() > 0);
    ASSERT(decodedSize.height() > 0);

    SkImageInfo info;
    info.fWidth = decodedSize.width();
    info.fHeight = decodedSize.height();
    info.fColorType = kBGRA_8888_SkColorType;
    info.fAlphaType = kPremul_SkAlphaType;

    SkBitmap bitmap;
    DecodingImageGenerator* generator = new DecodingImageGenerator(m_frameGenerator, info, index);
    bool installed = SkInstallDiscardablePixelRef(generator, &bitmap);
    ASSERT_UNUSED(installed, installed);
    bitmap.pixelRef()->setURI(labelDiscardable);
    generator->setGenerationId(bitmap.getGenerationID());
    return bitmap;
}

SkBitmap DeferredImageDecoder::createLazyDecodingBitmap(size_t index)
{
    IntSize decodedSize = m_actualDecoder->decodedSize();
    ASSERT(decodedSize.width() > 0);
    ASSERT(decodedSize.height() > 0);

    SkImageInfo info;
    info.fWidth = decodedSize.width();
    info.fHeight = decodedSize.height();
    info.fColorType = kPMColor_SkColorType;
    info.fAlphaType = kPremul_SkAlphaType;

    // Creates a lazily decoded SkPixelRef that references the entire image without scaling.
    SkBitmap bitmap;
    bitmap.setConfig(info);
    bitmap.setPixelRef(new LazyDecodingPixelRef(info, m_frameGenerator, index))->unref();

    // Use the URI to identify this as a lazily decoded SkPixelRef of type LazyDecodingPixelRef.
    // FIXME: It would be more useful to give the actual image URI.
    bitmap.pixelRef()->setURI(labelLazyDecoded);

    // Inform the bitmap that we will never change the pixels. This is a performance hint
    // subsystems that may try to cache this bitmap (e.g. pictures, pipes, gpu, pdf, etc.)
    bitmap.setImmutable();

    return bitmap;
}

bool DeferredImageDecoder::hotSpot(IntPoint& hotSpot) const
{
    // TODO: Implement.
    return m_actualDecoder ? m_actualDecoder->hotSpot(hotSpot) : false;
}

} // namespace WebCore
<|endoftext|>


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

#include "config.h"
#include "platform/graphics/GraphicsContextState.h"

#include "platform/graphics/skia/SkiaUtils.h"

namespace WebCore {

GraphicsContextState::GraphicsContextState()
    : m_fillColor(Color::black)
    , m_fillRule(RULE_NONZERO)
    , m_textDrawingMode(TextModeFill)
    , m_alpha(256)
    , m_xferMode(nullptr)
    , m_compositeOperator(CompositeSourceOver)
    , m_blendMode(blink::WebBlendModeNormal)
    , m_interpolationQuality(InterpolationDefault)
    , m_saveCount(0)
    , m_shouldAntialias(true)
    , m_shouldSmoothFonts(true)
    , m_shouldClampToSourceRect(true)
{
    m_strokePaint.setStyle(SkPaint::kStroke_Style);
    m_strokePaint.setStrokeWidth(SkFloatToScalar(m_strokeData.thickness()));
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
    m_strokePaint.setStrokeCap(SkPaint::kDefault_Cap);
    m_strokePaint.setStrokeJoin(SkPaint::kDefault_Join);
    m_strokePaint.setStrokeMiter(SkFloatToScalar(m_strokeData.miterLimit()));
    m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality));
    m_strokePaint.setAntiAlias(m_shouldAntialias);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
    m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality));
    m_fillPaint.setAntiAlias(m_shouldAntialias);
}

GraphicsContextState::GraphicsContextState(const GraphicsContextState& other)
    : m_strokePaint(other.m_strokePaint)
    , m_fillPaint(other.m_fillPaint)
    , m_strokeData(other.m_strokeData)
    , m_fillColor(other.m_fillColor)
    , m_fillRule(other.m_fillRule)
    , m_fillGradient(other.m_fillGradient)
    , m_fillPattern(other.m_fillPattern)
    , m_looper(other.m_looper)
    , m_textDrawingMode(other.m_textDrawingMode)
    , m_alpha(other.m_alpha)
    , m_xferMode(other.m_xferMode)
    , m_colorFilter(other.m_colorFilter)
    , m_compositeOperator(other.m_compositeOperator)
    , m_blendMode(other.m_blendMode)
    , m_interpolationQuality(other.m_interpolationQuality)
    , m_saveCount(0)
    , m_shouldAntialias(other.m_shouldAntialias)
    , m_shouldSmoothFonts(other.m_shouldSmoothFonts)
    , m_shouldClampToSourceRect(other.m_shouldClampToSourceRect) { }

void GraphicsContextState::copy(const GraphicsContextState& source)
{
    new (this) GraphicsContextState(source);
}

const SkPaint& GraphicsContextState::strokePaint(int strokedPathLength) const
{
    if (m_strokeData.gradient() && m_strokeData.gradient()->shaderChanged())
        m_strokePaint.setShader(m_strokeData.gradient()->shader());
    m_strokeData.setupPaintDashPathEffect(&m_strokePaint, strokedPathLength);
    return m_strokePaint;
}

const SkPaint& GraphicsContextState::fillPaint() const
{
    if (m_fillGradient && m_fillGradient->shaderChanged())
        m_fillPaint.setShader(m_fillGradient->shader());
    return m_fillPaint;
}

void GraphicsContextState::setStrokeStyle(StrokeStyle style)
{
    m_strokeData.setStyle(style);
}

void GraphicsContextState::setStrokeThickness(float thickness)
{
    m_strokeData.setThickness(thickness);
    m_strokePaint.setStrokeWidth(SkFloatToScalar(thickness));
}

void GraphicsContextState::setStrokeColor(const Color& color)
{
    m_strokeData.clearGradient();
    m_strokeData.clearPattern();
    m_strokeData.setColor(color);
    m_strokePaint.setColor(applyAlpha(color.rgb()));
    m_strokePaint.setShader(0);
}

void GraphicsContextState::setStrokeGradient(const PassRefPtr<Gradient> gradient)
{
    m_strokeData.setColor(Color::black);
    m_strokeData.clearPattern();
    m_strokeData.setGradient(gradient);
    m_strokePaint.setColor(applyAlpha(SK_ColorBLACK));
    m_strokePaint.setShader(m_strokeData.gradient()->shader());
}

void GraphicsContextState::clearStrokeGradient()
{
    m_strokeData.clearGradient();
    ASSERT(!m_strokeData.pattern());
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
}

void GraphicsContextState::setStrokePattern(const PassRefPtr<Pattern> pattern)
{
    m_strokeData.setColor(Color::black);
    m_strokeData.clearGradient();
    m_strokeData.setPattern(pattern);
    m_strokePaint.setColor(applyAlpha(SK_ColorBLACK));
    m_strokePaint.setShader(m_strokeData.pattern()->shader());
}

void GraphicsContextState::clearStrokePattern()
{
    m_strokeData.clearPattern();
    ASSERT(!m_strokeData.gradient());
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
}

void GraphicsContextState::setLineCap(LineCap cap)
{
    m_strokeData.setLineCap(cap);
    m_strokePaint.setStrokeCap((SkPaint::Cap)cap);
}

void GraphicsContextState::setLineJoin(LineJoin join)
{
    m_strokeData.setLineJoin(join);
    m_strokePaint.setStrokeJoin((SkPaint::Join)join);
}

void GraphicsContextState::setMiterLimit(float miterLimit)
{
    m_strokeData.setMiterLimit(miterLimit);
    m_strokePaint.setStrokeMiter(SkFloatToScalar(miterLimit));
}

void GraphicsContextState::setFillColor(const Color& color)
{
    m_fillColor = color;
    m_fillGradient.clear();
    m_fillPattern.clear();
    m_fillPaint.setColor(applyAlpha(color.rgb()));
    m_fillPaint.setShader(0);
}

void GraphicsContextState::setFillGradient(const PassRefPtr<Gradient> gradient)
{
    m_fillColor = Color::black;
    m_fillPattern.clear();
    m_fillGradient = gradient;
    m_fillPaint.setColor(applyAlpha(SK_ColorBLACK));
    m_fillPaint.setShader(m_fillGradient->shader());
}

void GraphicsContextState::clearFillGradient()
{
    m_fillGradient.clear();
    ASSERT(!m_fillPattern);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

void GraphicsContextState::setFillPattern(const PassRefPtr<Pattern> pattern)
{
    m_fillColor = Color::black;
    m_fillGradient.clear();
    m_fillPattern = pattern;
    m_fillPaint.setColor(applyAlpha(SK_ColorBLACK));
    m_fillPaint.setShader(m_fillPattern->shader());
}

void GraphicsContextState::clearFillPattern()
{
    m_fillPattern.clear();
    ASSERT(!m_fillGradient);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

// Shadow. (This will need tweaking if we use draw loopers for other things.)
void GraphicsContextState::setDrawLooper(PassRefPtr<SkDrawLooper> drawLooper)
{
    m_looper = drawLooper;
    m_strokePaint.setLooper(m_looper.get());
    m_fillPaint.setLooper(m_looper.get());
}

void GraphicsContextState::clearDrawLooper()
{
    m_looper.clear();
    m_strokePaint.setLooper(0);
    m_fillPaint.setLooper(0);
}

void GraphicsContextState::setAlphaAsFloat(float alpha)
{
    if (alpha < 0) {
        m_alpha = 0;
    } else {
        m_alpha = roundf(alpha * 256);
        if (m_alpha > 256)
            m_alpha = 256;
    }
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

void GraphicsContextState::setLineDash(const DashArray& dashes, float dashOffset)
{
    m_strokeData.setLineDash(dashes, dashOffset);
}

void GraphicsContextState::setColorFilter(PassRefPtr<SkColorFilter> colorFilter)
{
    m_colorFilter = colorFilter;
    m_strokePaint.setColorFilter(m_colorFilter.get());
    m_fillPaint.setColorFilter(m_colorFilter.get());
}

void GraphicsContextState::setCompositeOperation(CompositeOperator compositeOperation, blink::WebBlendMode blendMode)
{
    m_compositeOperator = compositeOperation;
    m_blendMode = blendMode;
    m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode);
    m_strokePaint.setXfermode(m_xferMode.get());
    m_fillPaint.setXfermode(m_xferMode.get());
}

void GraphicsContextState::setInterpolationQuality(InterpolationQuality quality)
{
    m_interpolationQuality = quality;
    m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality));
    m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality));
}

void GraphicsContextState::setShouldAntialias(bool shouldAntialias)
{
    m_shouldAntialias = shouldAntialias;
    m_strokePaint.setAntiAlias(shouldAntialias);
    m_fillPaint.setAntiAlias(shouldAntialias);
}

} // namespace WebCore
<commit_msg>Fix memory leak in GraphicsContextState.<commit_after>// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "platform/graphics/GraphicsContextState.h"

#include "platform/graphics/skia/SkiaUtils.h"

namespace WebCore {

GraphicsContextState::GraphicsContextState()
    : m_fillColor(Color::black)
    , m_fillRule(RULE_NONZERO)
    , m_textDrawingMode(TextModeFill)
    , m_alpha(256)
    , m_xferMode(nullptr)
    , m_compositeOperator(CompositeSourceOver)
    , m_blendMode(blink::WebBlendModeNormal)
    , m_interpolationQuality(InterpolationDefault)
    , m_saveCount(0)
    , m_shouldAntialias(true)
    , m_shouldSmoothFonts(true)
    , m_shouldClampToSourceRect(true)
{
    m_strokePaint.setStyle(SkPaint::kStroke_Style);
    m_strokePaint.setStrokeWidth(SkFloatToScalar(m_strokeData.thickness()));
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
    m_strokePaint.setStrokeCap(SkPaint::kDefault_Cap);
    m_strokePaint.setStrokeJoin(SkPaint::kDefault_Join);
    m_strokePaint.setStrokeMiter(SkFloatToScalar(m_strokeData.miterLimit()));
    m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality));
    m_strokePaint.setAntiAlias(m_shouldAntialias);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
    m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(m_interpolationQuality));
    m_fillPaint.setAntiAlias(m_shouldAntialias);
}

GraphicsContextState::GraphicsContextState(const GraphicsContextState& other)
    : m_strokePaint(other.m_strokePaint)
    , m_fillPaint(other.m_fillPaint)
    , m_strokeData(other.m_strokeData)
    , m_fillColor(other.m_fillColor)
    , m_fillRule(other.m_fillRule)
    , m_fillGradient(other.m_fillGradient)
    , m_fillPattern(other.m_fillPattern)
    , m_looper(other.m_looper)
    , m_textDrawingMode(other.m_textDrawingMode)
    , m_alpha(other.m_alpha)
    , m_xferMode(other.m_xferMode)
    , m_colorFilter(other.m_colorFilter)
    , m_compositeOperator(other.m_compositeOperator)
    , m_blendMode(other.m_blendMode)
    , m_interpolationQuality(other.m_interpolationQuality)
    , m_saveCount(0)
    , m_shouldAntialias(other.m_shouldAntialias)
    , m_shouldSmoothFonts(other.m_shouldSmoothFonts)
    , m_shouldClampToSourceRect(other.m_shouldClampToSourceRect) { }

void GraphicsContextState::copy(const GraphicsContextState& source)
{
    this->~GraphicsContextState();
    new (this) GraphicsContextState(source);
}

const SkPaint& GraphicsContextState::strokePaint(int strokedPathLength) const
{
    if (m_strokeData.gradient() && m_strokeData.gradient()->shaderChanged())
        m_strokePaint.setShader(m_strokeData.gradient()->shader());
    m_strokeData.setupPaintDashPathEffect(&m_strokePaint, strokedPathLength);
    return m_strokePaint;
}

const SkPaint& GraphicsContextState::fillPaint() const
{
    if (m_fillGradient && m_fillGradient->shaderChanged())
        m_fillPaint.setShader(m_fillGradient->shader());
    return m_fillPaint;
}

void GraphicsContextState::setStrokeStyle(StrokeStyle style)
{
    m_strokeData.setStyle(style);
}

void GraphicsContextState::setStrokeThickness(float thickness)
{
    m_strokeData.setThickness(thickness);
    m_strokePaint.setStrokeWidth(SkFloatToScalar(thickness));
}

void GraphicsContextState::setStrokeColor(const Color& color)
{
    m_strokeData.clearGradient();
    m_strokeData.clearPattern();
    m_strokeData.setColor(color);
    m_strokePaint.setColor(applyAlpha(color.rgb()));
    m_strokePaint.setShader(0);
}

void GraphicsContextState::setStrokeGradient(const PassRefPtr<Gradient> gradient)
{
    m_strokeData.setColor(Color::black);
    m_strokeData.clearPattern();
    m_strokeData.setGradient(gradient);
    m_strokePaint.setColor(applyAlpha(SK_ColorBLACK));
    m_strokePaint.setShader(m_strokeData.gradient()->shader());
}

void GraphicsContextState::clearStrokeGradient()
{
    m_strokeData.clearGradient();
    ASSERT(!m_strokeData.pattern());
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
}

void GraphicsContextState::setStrokePattern(const PassRefPtr<Pattern> pattern)
{
    m_strokeData.setColor(Color::black);
    m_strokeData.clearGradient();
    m_strokeData.setPattern(pattern);
    m_strokePaint.setColor(applyAlpha(SK_ColorBLACK));
    m_strokePaint.setShader(m_strokeData.pattern()->shader());
}

void GraphicsContextState::clearStrokePattern()
{
    m_strokeData.clearPattern();
    ASSERT(!m_strokeData.gradient());
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
}

void GraphicsContextState::setLineCap(LineCap cap)
{
    m_strokeData.setLineCap(cap);
    m_strokePaint.setStrokeCap((SkPaint::Cap)cap);
}

void GraphicsContextState::setLineJoin(LineJoin join)
{
    m_strokeData.setLineJoin(join);
    m_strokePaint.setStrokeJoin((SkPaint::Join)join);
}

void GraphicsContextState::setMiterLimit(float miterLimit)
{
    m_strokeData.setMiterLimit(miterLimit);
    m_strokePaint.setStrokeMiter(SkFloatToScalar(miterLimit));
}

void GraphicsContextState::setFillColor(const Color& color)
{
    m_fillColor = color;
    m_fillGradient.clear();
    m_fillPattern.clear();
    m_fillPaint.setColor(applyAlpha(color.rgb()));
    m_fillPaint.setShader(0);
}

void GraphicsContextState::setFillGradient(const PassRefPtr<Gradient> gradient)
{
    m_fillColor = Color::black;
    m_fillPattern.clear();
    m_fillGradient = gradient;
    m_fillPaint.setColor(applyAlpha(SK_ColorBLACK));
    m_fillPaint.setShader(m_fillGradient->shader());
}

void GraphicsContextState::clearFillGradient()
{
    m_fillGradient.clear();
    ASSERT(!m_fillPattern);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

void GraphicsContextState::setFillPattern(const PassRefPtr<Pattern> pattern)
{
    m_fillColor = Color::black;
    m_fillGradient.clear();
    m_fillPattern = pattern;
    m_fillPaint.setColor(applyAlpha(SK_ColorBLACK));
    m_fillPaint.setShader(m_fillPattern->shader());
}

void GraphicsContextState::clearFillPattern()
{
    m_fillPattern.clear();
    ASSERT(!m_fillGradient);
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

// Shadow. (This will need tweaking if we use draw loopers for other things.)
void GraphicsContextState::setDrawLooper(PassRefPtr<SkDrawLooper> drawLooper)
{
    m_looper = drawLooper;
    m_strokePaint.setLooper(m_looper.get());
    m_fillPaint.setLooper(m_looper.get());
}

void GraphicsContextState::clearDrawLooper()
{
    m_looper.clear();
    m_strokePaint.setLooper(0);
    m_fillPaint.setLooper(0);
}

void GraphicsContextState::setAlphaAsFloat(float alpha)
{
    if (alpha < 0) {
        m_alpha = 0;
    } else {
        m_alpha = roundf(alpha * 256);
        if (m_alpha > 256)
            m_alpha = 256;
    }
    m_strokePaint.setColor(applyAlpha(m_strokeData.color().rgb()));
    m_fillPaint.setColor(applyAlpha(m_fillColor.rgb()));
}

void GraphicsContextState::setLineDash(const DashArray& dashes, float dashOffset)
{
    m_strokeData.setLineDash(dashes, dashOffset);
}

void GraphicsContextState::setColorFilter(PassRefPtr<SkColorFilter> colorFilter)
{
    m_colorFilter = colorFilter;
    m_strokePaint.setColorFilter(m_colorFilter.get());
    m_fillPaint.setColorFilter(m_colorFilter.get());
}

void GraphicsContextState::setCompositeOperation(CompositeOperator compositeOperation, blink::WebBlendMode blendMode)
{
    m_compositeOperator = compositeOperation;
    m_blendMode = blendMode;
    m_xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode);
    m_strokePaint.setXfermode(m_xferMode.get());
    m_fillPaint.setXfermode(m_xferMode.get());
}

void GraphicsContextState::setInterpolationQuality(InterpolationQuality quality)
{
    m_interpolationQuality = quality;
    m_strokePaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality));
    m_fillPaint.setFilterLevel(WebCoreInterpolationQualityToSkFilterLevel(quality));
}

void GraphicsContextState::setShouldAntialias(bool shouldAntialias)
{
    m_shouldAntialias = shouldAntialias;
    m_strokePaint.setAntiAlias(shouldAntialias);
    m_fillPaint.setAntiAlias(shouldAntialias);
}

} // namespace WebCore
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Testing/VisualTestCommon/GlutRenderer.h"

#include <string>

using SurgSim::Math::Vector3d;
using SurgSim::Math::RigidTransform3d;

int GlutRenderer::m_width = 1024;
int GlutRenderer::m_height = 768;

std::shared_ptr<GlutCamera> GlutRenderer::m_camera = nullptr;
std::vector< std::shared_ptr<GlutRenderObject> > GlutRenderer::m_objects =
	std::vector< std::shared_ptr<GlutRenderObject> >();

GlutRenderObject::~GlutRenderObject()
{
}

void GlutSquare::draw()
{
	glEnable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	Vector3d squarePoints[4];
	squarePoints[0] = - (halfSize * planeDirectionX) + (halfSize * planeDirectionY);
	squarePoints[1] =   (halfSize * planeDirectionX) + (halfSize * planeDirectionY);
	squarePoints[2] =   (halfSize * planeDirectionX) - (halfSize * planeDirectionY);
	squarePoints[3] = - (halfSize * planeDirectionX) - (halfSize * planeDirectionY);

	Vector3d normal = (squarePoints[1] - squarePoints[0]).cross(squarePoints[2] - squarePoints[0]);
	normal.normalize();

	glColor3d(color.x(), color.y(), color.z());
	glBegin(GL_QUADS);

	// Front side
	glNormal3d(normal.x(), normal.y(), normal.z());
	for (int i = 0; i < 4; ++i)
	{
		glVertex3d(squarePoints[i].x(), squarePoints[i].y(), squarePoints[i].z());
	}
	// Back side
	glNormal3d(- normal.x(), - normal.y(), - normal.z());
	for (int i = 0; i < 4; ++i)
	{
		glVertex3d(squarePoints[3 - i].x(), squarePoints[3 - i].y(), squarePoints[3 - i].z());
	}

	glEnd();

	glPopMatrix();
}

void GlutAxes::draw()
{
	glDisable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	Vector3d axesPoints[4];
	axesPoints[0] = Vector3d(0.0, 0.0, 0.0);
	axesPoints[1] = (length * Vector3d(1.0, 0.0, 0.0));
	axesPoints[2] = (length * Vector3d(0.0, 1.0, 0.0));
	axesPoints[3] = (length * Vector3d(0.0, 0.0, 1.0));

	glLineWidth(width);

	glBegin(GL_LINES);
	glColor3d(1.0, 0.0, 0.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[1].x(), axesPoints[1].y(), axesPoints[1].z());
	glColor3d(0.0, 1.0, 0.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[2].x(), axesPoints[2].y(), axesPoints[2].z());
	glColor3d(0.0, 0.0, 1.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[3].x(), axesPoints[3].y(), axesPoints[3].z());
	glEnd();

	glPopMatrix();
}

void GlutSphere::draw()
{
	glEnable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	glColor3d(color.x(), color.y(), color.z());

	gluQuadricOrientation(quadratic, GLU_OUTSIDE);
	gluSphere(quadratic, radius, 32, 32);

	glPopMatrix();
}

void GlutGroup::draw()
{
	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	for (auto it = children.cbegin(); it != children.cend(); ++it)
	{
		(*it)->draw();
	}

	glPopMatrix();
}

void GlutRenderer::initialize()
{
	char* argv[1];
	int argc = 1;
	std::string title = "GlutWindow";
	std::vector<char> charString(title.size() + 1);
	std::copy(title.begin(), title.end(), charString.begin());
	argv[0] = &charString[0];
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(m_width, m_height);
	glutCreateWindow("Simple GLUT display");

	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
}
void GlutRenderer::display()
{
	glViewport(0, 0, (GLsizei) m_width, (GLsizei) m_height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(m_camera->fovY, static_cast<float>(m_width) / m_height, m_camera->zNear, m_camera->zFar);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(m_camera->eye.x(), m_camera->eye.y(), m_camera->eye.z(),
			  m_camera->center.x(), m_camera->center.y(), m_camera->center.z(),
			  m_camera->up.x(), m_camera->up.y(), m_camera->up.z());

	glEnable(GL_LIGHT0);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	drawObjects();
	glutSwapBuffers();

	glutPostRedisplay();
}
<commit_msg>Check if camera is null before using in GlutRenderer<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Testing/VisualTestCommon/GlutRenderer.h"

#include <string>

using SurgSim::Math::Vector3d;
using SurgSim::Math::RigidTransform3d;

int GlutRenderer::m_width = 1024;
int GlutRenderer::m_height = 768;

std::shared_ptr<GlutCamera> GlutRenderer::m_camera = nullptr;
std::vector< std::shared_ptr<GlutRenderObject> > GlutRenderer::m_objects =
	std::vector< std::shared_ptr<GlutRenderObject> >();

GlutRenderObject::~GlutRenderObject()
{
}

void GlutSquare::draw()
{
	glEnable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	Vector3d squarePoints[4];
	squarePoints[0] = - (halfSize * planeDirectionX) + (halfSize * planeDirectionY);
	squarePoints[1] =   (halfSize * planeDirectionX) + (halfSize * planeDirectionY);
	squarePoints[2] =   (halfSize * planeDirectionX) - (halfSize * planeDirectionY);
	squarePoints[3] = - (halfSize * planeDirectionX) - (halfSize * planeDirectionY);

	Vector3d normal = (squarePoints[1] - squarePoints[0]).cross(squarePoints[2] - squarePoints[0]);
	normal.normalize();

	glColor3d(color.x(), color.y(), color.z());
	glBegin(GL_QUADS);

	// Front side
	glNormal3d(normal.x(), normal.y(), normal.z());
	for (int i = 0; i < 4; ++i)
	{
		glVertex3d(squarePoints[i].x(), squarePoints[i].y(), squarePoints[i].z());
	}
	// Back side
	glNormal3d(- normal.x(), - normal.y(), - normal.z());
	for (int i = 0; i < 4; ++i)
	{
		glVertex3d(squarePoints[3 - i].x(), squarePoints[3 - i].y(), squarePoints[3 - i].z());
	}

	glEnd();

	glPopMatrix();
}

void GlutAxes::draw()
{
	glDisable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	Vector3d axesPoints[4];
	axesPoints[0] = Vector3d(0.0, 0.0, 0.0);
	axesPoints[1] = (length * Vector3d(1.0, 0.0, 0.0));
	axesPoints[2] = (length * Vector3d(0.0, 1.0, 0.0));
	axesPoints[3] = (length * Vector3d(0.0, 0.0, 1.0));

	glLineWidth(width);

	glBegin(GL_LINES);
	glColor3d(1.0, 0.0, 0.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[1].x(), axesPoints[1].y(), axesPoints[1].z());
	glColor3d(0.0, 1.0, 0.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[2].x(), axesPoints[2].y(), axesPoints[2].z());
	glColor3d(0.0, 0.0, 1.0);
	glVertex3d(axesPoints[0].x(), axesPoints[0].y(), axesPoints[0].z());
	glVertex3d(axesPoints[3].x(), axesPoints[3].y(), axesPoints[3].z());
	glEnd();

	glPopMatrix();
}

void GlutSphere::draw()
{
	glEnable(GL_LIGHTING);

	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	glColor3d(color.x(), color.y(), color.z());

	gluQuadricOrientation(quadratic, GLU_OUTSIDE);
	gluSphere(quadratic, radius, 32, 32);

	glPopMatrix();
}

void GlutGroup::draw()
{
	glPushMatrix();

	glTranslated(pose.translation().x(), pose.translation().y(), pose.translation().z());
	Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(pose.rotation());
	glRotated(angleAxis.angle() * 180.0 / M_PI, angleAxis.axis().x(), angleAxis.axis().y(), angleAxis.axis().z());

	for (auto it = children.cbegin(); it != children.cend(); ++it)
	{
		(*it)->draw();
	}

	glPopMatrix();
}

void GlutRenderer::initialize()
{
	char* argv[1];
	int argc = 1;
	std::string title = "GlutWindow";
	std::vector<char> charString(title.size() + 1);
	std::copy(title.begin(), title.end(), charString.begin());
	argv[0] = &charString[0];
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(m_width, m_height);
	glutCreateWindow("Simple GLUT display");

	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
}
void GlutRenderer::display()
{
	glViewport(0, 0, (GLsizei) m_width, (GLsizei) m_height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (m_camera)
	{
		gluPerspective(m_camera->fovY, static_cast<float>(m_width) / m_height, m_camera->zNear, m_camera->zFar);
	}

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	if (m_camera)
	{
		gluLookAt(m_camera->eye.x(), m_camera->eye.y(), m_camera->eye.z(),
				  m_camera->center.x(), m_camera->center.y(), m_camera->center.z(),
				  m_camera->up.x(), m_camera->up.y(), m_camera->up.z());
	}

	glEnable(GL_LIGHT0);

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	drawObjects();
	glutSwapBuffers();

	glutPostRedisplay();
}
<|endoftext|>


<commit_before>#include "musiclrcfloatphotowidget.h"
#include "musicbackgroundmanager.h"
#include "musicclickedlabel.h"

#include <qmath.h>
#include <QTimer>
#include <QCheckBox>
#include <QPushButton>
#include <QButtonGroup>

MusicLrcFloatPhotoWidget::MusicLrcFloatPhotoWidget(QWidget *parent)
    : MusicFloatAbstractWidget(parent)
{
    setObjectName("MusicLrcFloatPhotoWidget");
    setStyleSheet(QString("#MusicLrcFloatPhotoWidget{%1}").arg(MusicUIObject::MBackgroundStyle08));

    m_filmBGWidget = new QWidget(this);
    m_filmBGWidget->setGeometry(0, 0, 662, 125);
    m_filmBGWidget->setStyleSheet("background-image:url(':/lrc/lb_film_bg');");

    m_plane1 = new MusicClickedLabel(this);
    m_plane1->setGeometry(100, 30, PHOTO_WIDTH, PHOTO_HEIGHT);
    m_plane2 = new MusicClickedLabel(this);
    m_plane2->setGeometry(280, 30, PHOTO_WIDTH, PHOTO_HEIGHT);
    m_plane3 = new MusicClickedLabel(this);
    m_plane3->setGeometry(460, 30, PHOTO_WIDTH, PHOTO_HEIGHT);

    m_radio1 = new QCheckBox(this);
    m_radio1->setGeometry(190, 75, 20, 20);
    m_radio1->setStyleSheet(MusicUIObject::MCheckBoxStyle01);
    m_radio2 = new QCheckBox(this);
    m_radio2->setGeometry(370, 75, 20, 20);
    m_radio2->setStyleSheet(MusicUIObject::MCheckBoxStyle01);
    m_radio3 = new QCheckBox(this);
    m_radio3->setGeometry(550, 75, 20, 20);
    m_radio3->setStyleSheet(MusicUIObject::MCheckBoxStyle01);

    m_checkBox = new QCheckBox(tr("All"), this);
    m_checkBox->setGeometry(15, 130, 100, 20);
    m_checkBox->setChecked(true);
    m_checkBox->setStyleSheet(MusicUIObject::MCheckBoxStyle01);

    m_confirmButton = new QPushButton(tr("Confirm"), this);
    m_confirmButton->setGeometry(500, 130, 70, 20);
    m_confirmButton->setStyleSheet(MusicUIObject::MPushButtonStyle04);
    m_confirmButton->setCursor(QCursor(Qt::PointingHandCursor));

    m_previous = new QPushButton("<", this);
    m_previous->setGeometry(20, 38, 15, 50);
    m_next = new QPushButton(">", this);
    m_next->setGeometry(625, 38, 15, 50);
    m_previous->setCursor(QCursor(Qt::PointingHandCursor));
    m_next->setCursor(QCursor(Qt::PointingHandCursor));

    m_previous->setStyleSheet(MusicUIObject::MBackgroundStyle10 + MusicUIObject::MBorderStyle01);
    m_next->setStyleSheet(MusicUIObject::MBackgroundStyle10 + MusicUIObject::MBorderStyle01);

    m_currentIndex = 0;

    connect(m_confirmButton, SIGNAL(clicked()), SLOT(confirmButtonClicked()));
    connect(m_previous, SIGNAL(clicked()), SLOT(photoPrevious()));
    connect(m_next, SIGNAL(clicked()), SLOT(photoNext()));
    connect(m_plane1, SIGNAL(clicked()), SLOT(sendUserSelectArtBg1()));
    connect(m_plane2, SIGNAL(clicked()), SLOT(sendUserSelectArtBg2()));
    connect(m_plane3, SIGNAL(clicked()), SLOT(sendUserSelectArtBg3()));

    QButtonGroup *radioGroup = new QButtonGroup(this);
    radioGroup->setExclusive(false);
    radioGroup->addButton(m_radio1, 0);
    radioGroup->addButton(m_radio2, 1);
    radioGroup->addButton(m_radio3, 2);
    connect(radioGroup, SIGNAL(buttonClicked(int)), SLOT(userSelectCheckBoxChecked(int)));
    connect(M_BACKGROUND_PTR, SIGNAL(artHasChanged()), SLOT(artHasChanged()));
    connect(m_checkBox, SIGNAL(clicked(bool)), SLOT(selectAllStateChanged(bool)));
}

MusicLrcFloatPhotoWidget::~MusicLrcFloatPhotoWidget()
{
    delete m_radio1;
    delete m_radio2;
    delete m_radio3;
    delete m_plane1;
    delete m_plane2;
    delete m_plane3;
    delete m_filmBGWidget;
    delete m_previous;
    delete m_next;
    delete m_confirmButton;
    delete m_checkBox;
}

QString MusicLrcFloatPhotoWidget::getClassName()
{
    return staticMetaObject.className();
}

void MusicLrcFloatPhotoWidget::resizeWindow(int width, int height)
{
    m_rectIn = QRect(width/2, 530 + height, 115, 105);
    m_rectOut = QRect(width/2, 330 + height, 662, 180);
    setGeometry(m_rectOut);
}

void MusicLrcFloatPhotoWidget::show()
{
    QWidget::show();
    animationOut();
    showPhoto();
}

void MusicLrcFloatPhotoWidget::close()
{
    animationIn();
    QTimer::singleShot(m_animation->duration(), this, SLOT(parentClose()));
}

void MusicLrcFloatPhotoWidget::confirmButtonClicked()
{
    QStringList list;
    foreach(int i, m_selectNum)
    {
       list << m_artPath[i];
    }
    M_BACKGROUND_PTR->setArtPhotoPaths(list);
    close();
}

void MusicLrcFloatPhotoWidget::showPhoto() const
{
    m_previous->setEnabled(m_currentIndex != 0);
    int page = ceil(m_artPath.count() *1.0 / PHOTO_PERLINE) - 1;
    m_next->setEnabled(m_currentIndex != (page = page < 0 ? 0 : page) );

    QPixmap nullPix;
    nullPix.fill(Qt::black);
    //check show pixmap
    int indexCheck = m_currentIndex * PHOTO_PERLINE;
    m_plane1->setPixmap( (indexCheck + 0) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 0] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    m_plane2->setPixmap( (indexCheck + 1) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 1] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    m_plane3->setPixmap( (indexCheck + 2) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 2] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    //check show radio button
    m_radio1->setChecked( m_selectNum.contains(indexCheck + 0) );
    m_radio2->setChecked( m_selectNum.contains(indexCheck + 1) );
    m_radio3->setChecked( m_selectNum.contains(indexCheck + 2) );
    m_radio1->setVisible( (indexCheck + 0) < m_artPath.count() );
    m_radio2->setVisible( (indexCheck + 1) < m_artPath.count() );
    m_radio3->setVisible( (indexCheck + 2) < m_artPath.count() );
}

void MusicLrcFloatPhotoWidget::photoPrevious()
{
    if(--m_currentIndex < 0)
    {
        m_currentIndex = 0;
    }
    showPhoto();
}

void MusicLrcFloatPhotoWidget::artHasChanged()
{
    m_selectNum.clear();
    m_artPath = M_BACKGROUND_PTR->getArtPhotoPaths();
    for(int i=0; i<m_artPath.count(); ++i)
    {
        m_selectNum << i;
    }
}

void MusicLrcFloatPhotoWidget::photoNext()
{
    int page = ceil(m_artPath.count() *1.0 / PHOTO_PERLINE) - 1;
    if( ++m_currentIndex > (page = page < 0 ? 0 : page) )
    {
        m_currentIndex = page;
    }
    showPhoto();
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg1()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 0);
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg2()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 1);
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg3()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 2);
}

void MusicLrcFloatPhotoWidget::userSelectCheckBoxChecked(int index)
{
    bool status = true;
    switch(index)
    {
        case 0: status = m_radio1->isChecked(); break;
        case 1: status = m_radio2->isChecked(); break;
        case 2: status = m_radio3->isChecked(); break;
        default: break;
    }
    index = m_currentIndex * PHOTO_PERLINE + index;
    if(status)
    {
        m_selectNum << index;
    }
    else
    {
        m_selectNum.remove(index);
    }

    m_checkBox->setChecked(false);
}

void MusicLrcFloatPhotoWidget::selectAllStateChanged(bool state)
{
    if(state)
    {
        for(int i=0; i<m_artPath.count(); ++i)
        {
            m_selectNum << i;
        }
        showPhoto();
    }
    else
    {
        m_radio1->setChecked(false);
        m_radio2->setChecked(false);
        m_radio3->setChecked(false);
        m_selectNum.clear();
    }
}
<commit_msg>Optimized the float photo style[388974]<commit_after>#include "musiclrcfloatphotowidget.h"
#include "musicbackgroundmanager.h"
#include "musicclickedlabel.h"
#include "musicinlinefloatuiobject.h"

#include <qmath.h>
#include <QTimer>
#include <QCheckBox>
#include <QPushButton>
#include <QButtonGroup>

MusicLrcFloatPhotoWidget::MusicLrcFloatPhotoWidget(QWidget *parent)
    : MusicFloatAbstractWidget(parent)
{
    setObjectName("MusicLrcFloatPhotoWidget");
    setStyleSheet(QString("#MusicLrcFloatPhotoWidget{%1}").arg(MusicUIObject::MBackgroundStyle08));

    m_filmBGWidget = new QWidget(this);
    m_filmBGWidget->setGeometry(0, 0, 662, 125);
    m_filmBGWidget->setStyleSheet("background-image:url(':/lrc/lb_film_bg');");

    m_plane1 = new MusicClickedLabel(this);
    m_plane1->setGeometry(100, 30, PHOTO_WIDTH, PHOTO_HEIGHT);
    m_plane2 = new MusicClickedLabel(this);
    m_plane2->setGeometry(280, 30, PHOTO_WIDTH, PHOTO_HEIGHT);
    m_plane3 = new MusicClickedLabel(this);
    m_plane3->setGeometry(460, 30, PHOTO_WIDTH, PHOTO_HEIGHT);

    m_radio1 = new QCheckBox(this);
    m_radio1->setGeometry(190, 75, 20, 20);
    m_radio1->setStyleSheet(MusicUIObject::MCheckBoxStyle01);
    m_radio2 = new QCheckBox(this);
    m_radio2->setGeometry(370, 75, 20, 20);
    m_radio2->setStyleSheet(MusicUIObject::MCheckBoxStyle01);
    m_radio3 = new QCheckBox(this);
    m_radio3->setGeometry(550, 75, 20, 20);
    m_radio3->setStyleSheet(MusicUIObject::MCheckBoxStyle01);

    m_checkBox = new QCheckBox(tr("All"), this);
    m_checkBox->setGeometry(15, 130, 100, 20);
    m_checkBox->setChecked(true);
    m_checkBox->setStyleSheet(MusicUIObject::MCheckBoxStyle01);

    m_confirmButton = new QPushButton(tr("Confirm"), this);
    m_confirmButton->setGeometry(515, 130, 60, 22);
    m_confirmButton->setStyleSheet(MusicUIObject::MKGInlineFloatSetting + \
                                   MusicUIObject::MPushButtonStyle08);
    m_confirmButton->setCursor(QCursor(Qt::PointingHandCursor));

    m_previous = new QPushButton("<", this);
    m_previous->setGeometry(20, 38, 15, 50);
    m_next = new QPushButton(">", this);
    m_next->setGeometry(625, 38, 15, 50);
    m_previous->setCursor(QCursor(Qt::PointingHandCursor));
    m_next->setCursor(QCursor(Qt::PointingHandCursor));

    m_previous->setStyleSheet(MusicUIObject::MBackgroundStyle10 + MusicUIObject::MBorderStyle01);
    m_next->setStyleSheet(MusicUIObject::MBackgroundStyle10 + MusicUIObject::MBorderStyle01);

    m_currentIndex = 0;

    connect(m_confirmButton, SIGNAL(clicked()), SLOT(confirmButtonClicked()));
    connect(m_previous, SIGNAL(clicked()), SLOT(photoPrevious()));
    connect(m_next, SIGNAL(clicked()), SLOT(photoNext()));
    connect(m_plane1, SIGNAL(clicked()), SLOT(sendUserSelectArtBg1()));
    connect(m_plane2, SIGNAL(clicked()), SLOT(sendUserSelectArtBg2()));
    connect(m_plane3, SIGNAL(clicked()), SLOT(sendUserSelectArtBg3()));

    QButtonGroup *radioGroup = new QButtonGroup(this);
    radioGroup->setExclusive(false);
    radioGroup->addButton(m_radio1, 0);
    radioGroup->addButton(m_radio2, 1);
    radioGroup->addButton(m_radio3, 2);
    connect(radioGroup, SIGNAL(buttonClicked(int)), SLOT(userSelectCheckBoxChecked(int)));
    connect(M_BACKGROUND_PTR, SIGNAL(artHasChanged()), SLOT(artHasChanged()));
    connect(m_checkBox, SIGNAL(clicked(bool)), SLOT(selectAllStateChanged(bool)));
}

MusicLrcFloatPhotoWidget::~MusicLrcFloatPhotoWidget()
{
    delete m_radio1;
    delete m_radio2;
    delete m_radio3;
    delete m_plane1;
    delete m_plane2;
    delete m_plane3;
    delete m_filmBGWidget;
    delete m_previous;
    delete m_next;
    delete m_confirmButton;
    delete m_checkBox;
}

QString MusicLrcFloatPhotoWidget::getClassName()
{
    return staticMetaObject.className();
}

void MusicLrcFloatPhotoWidget::resizeWindow(int width, int height)
{
    m_rectIn = QRect(width/2, 530 + height, 115, 105);
    m_rectOut = QRect(width/2, 330 + height, 662, 180);
    setGeometry(m_rectOut);
}

void MusicLrcFloatPhotoWidget::show()
{
    QWidget::show();
    animationOut();
    showPhoto();
}

void MusicLrcFloatPhotoWidget::close()
{
    animationIn();
    QTimer::singleShot(m_animation->duration(), this, SLOT(parentClose()));
}

void MusicLrcFloatPhotoWidget::confirmButtonClicked()
{
    QStringList list;
    foreach(int i, m_selectNum)
    {
       list << m_artPath[i];
    }
    M_BACKGROUND_PTR->setArtPhotoPaths(list);
    close();
}

void MusicLrcFloatPhotoWidget::showPhoto() const
{
    m_previous->setEnabled(m_currentIndex != 0);
    int page = ceil(m_artPath.count() *1.0 / PHOTO_PERLINE) - 1;
    m_next->setEnabled(m_currentIndex != (page = page < 0 ? 0 : page) );

    QPixmap nullPix;
    nullPix.fill(Qt::black);
    //check show pixmap
    int indexCheck = m_currentIndex * PHOTO_PERLINE;
    m_plane1->setPixmap( (indexCheck + 0) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 0] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    m_plane2->setPixmap( (indexCheck + 1) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 1] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    m_plane3->setPixmap( (indexCheck + 2) < m_artPath.count() ? QPixmap( m_artPath[indexCheck + 2] )
                                           .scaled(PHOTO_WIDTH, PHOTO_HEIGHT): nullPix );
    //check show radio button
    m_radio1->setChecked( m_selectNum.contains(indexCheck + 0) );
    m_radio2->setChecked( m_selectNum.contains(indexCheck + 1) );
    m_radio3->setChecked( m_selectNum.contains(indexCheck + 2) );
    m_radio1->setVisible( (indexCheck + 0) < m_artPath.count() );
    m_radio2->setVisible( (indexCheck + 1) < m_artPath.count() );
    m_radio3->setVisible( (indexCheck + 2) < m_artPath.count() );
}

void MusicLrcFloatPhotoWidget::photoPrevious()
{
    if(--m_currentIndex < 0)
    {
        m_currentIndex = 0;
    }
    showPhoto();
}

void MusicLrcFloatPhotoWidget::artHasChanged()
{
    m_selectNum.clear();
    m_artPath = M_BACKGROUND_PTR->getArtPhotoPaths();
    for(int i=0; i<m_artPath.count(); ++i)
    {
        m_selectNum << i;
    }
}

void MusicLrcFloatPhotoWidget::photoNext()
{
    int page = ceil(m_artPath.count() *1.0 / PHOTO_PERLINE) - 1;
    if( ++m_currentIndex > (page = page < 0 ? 0 : page) )
    {
        m_currentIndex = page;
    }
    showPhoto();
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg1()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 0);
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg2()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 1);
}

void MusicLrcFloatPhotoWidget::sendUserSelectArtBg3()
{
    M_BACKGROUND_PTR->setUserSelectArtIndex(m_currentIndex * PHOTO_PERLINE + 2);
}

void MusicLrcFloatPhotoWidget::userSelectCheckBoxChecked(int index)
{
    bool status = true;
    switch(index)
    {
        case 0: status = m_radio1->isChecked(); break;
        case 1: status = m_radio2->isChecked(); break;
        case 2: status = m_radio3->isChecked(); break;
        default: break;
    }
    index = m_currentIndex * PHOTO_PERLINE + index;
    if(status)
    {
        m_selectNum << index;
    }
    else
    {
        m_selectNum.remove(index);
    }

    m_checkBox->setChecked(false);
}

void MusicLrcFloatPhotoWidget::selectAllStateChanged(bool state)
{
    if(state)
    {
        for(int i=0; i<m_artPath.count(); ++i)
        {
            m_selectNum << i;
        }
        showPhoto();
    }
    else
    {
        m_radio1->setChecked(false);
        m_radio2->setChecked(false);
        m_radio3->setChecked(false);
        m_selectNum.clear();
    }
}
<|endoftext|>


<commit_before>#include "statisticswindow.h"
#include "ui_statisticswindow.h"

#include <QCloseEvent>
#include <QDateTime>
#include <QDebug>

const int BUFFERSIZE = 65536;

StatisticsWindow::StatisticsWindow(QWidget *parent) :
QDialog(parent),
StatisticsInterface(),
ui_(new Ui::StatisticsWindow),
  framerate_(0),
  videoIndex_(0), // ringbuffer index
  videoPackets_(BUFFERSIZE,0), // ringbuffer
  audioIndex_(0), // ringbuffer index
  audioPackets_(BUFFERSIZE,0), // ringbuffer
  sendPacketCount_(0),
  transferredData_(0),
  receivePacketCount_(0),
  receivedData_(0),
  packetsDropped_(0),
  lastVideoBitrate_(0),
  lastAudioBitrate_(0)
{
  ui_->setupUi(this);
  ui_->participantTable->setColumnCount(4); // more columns can be added later
  ui_->participantTable->setHorizontalHeaderItem(0, new QTableWidgetItem(QString("IP")));
  ui_->participantTable->setHorizontalHeaderItem(1, new QTableWidgetItem(QString("Port")));
  ui_->participantTable->setHorizontalHeaderItem(2, new QTableWidgetItem(QString("Audio delay")));
  ui_->participantTable->setHorizontalHeaderItem(3, new QTableWidgetItem(QString("Video delay")));
}

StatisticsWindow::~StatisticsWindow()
{
  delete ui_;
}

void StatisticsWindow::closeEvent(QCloseEvent *event)
{
  accept();
}

void StatisticsWindow::addNextInterface(StatisticsInterface* next)
{}

void StatisticsWindow::videoInfo(double framerate, QSize resolution)
{
  framerate_ = framerate;
  ui_->framerate_value->setText( QString::number(framerate)+" fps");
  ui_->resolution_value->setText( QString::number(resolution.width()) + "x"
                          + QString::number(resolution.height()));
}

void StatisticsWindow::audioInfo(uint32_t sampleRate, uint16_t channelCount)
{
  //ui_->a_framerate_value->setText(QString::number(framerate)+"fps");
  ui_->channels_value->setText(QString::number(channelCount));
  ui_->sample_rate_value->setText(QString::number(sampleRate) + " Hz");
}

void StatisticsWindow::addParticipant(QString ip, QString port)
{
  ui_->participantTable->insertRow(ui_->participantTable->rowCount());
  // add cells to table
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 0, new QTableWidgetItem(ip));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 1, new QTableWidgetItem(port));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 2, new QTableWidgetItem("- ms"));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 3, new QTableWidgetItem("- ms"));

  delays_.push_back({0,0});

}

void StatisticsWindow::sendDelay(QString type, uint32_t delay)
{
  if(type == "video" || type == "Video")
  {
    sendMutex_.lock();
    ui_->encode_delay_value->setText( QString::number(delay) + " ms. (not precise)" );
    sendMutex_.unlock();
  }
  else if(type == "audio" || type == "Audio")
  {
    sendMutex_.lock();
    ui_->audio_delay_value->setText( QString::number(delay) + " ms. (not precise)" );
    sendMutex_.unlock();
  }
}

void StatisticsWindow::receiveDelay(uint32_t peer, QString type, int32_t delay)
{
  if(type == "video" || type == "Video")
  {
    delays_.at(peer).video = delay;
    //ui_->participantTable->setItem(peer, 3, new QTableWidgetItem( QString::number(delay) + " ms"));
  }
  else if(type == "audio" || type == "Audio")
  {
    delays_.at(peer).audio = delay;
    //ui_->participantTable->setItem(peer, 2, new QTableWidgetItem( QString::number(delay) + " ms"));
  }
}

void StatisticsWindow::addEncodedPacket(QString type, uint16_t size)
{
  PacketInfo *packet = new PacketInfo{QDateTime::currentMSecsSinceEpoch(), size};

  if(type == "video" || type == "Video")
  {
    if(videoPackets_[videoIndex_%BUFFERSIZE])
    {
      delete videoPackets_.at(videoIndex_%BUFFERSIZE);
    }

    videoPackets_[videoIndex_%BUFFERSIZE] = packet;

    ++videoIndex_;
  }
  else if(type == "audio" || type == "Audio")
  {
    if(audioPackets_[audioIndex_%BUFFERSIZE])
    {
      delete audioPackets_.at(audioIndex_%BUFFERSIZE);
    }

    audioPackets_[audioIndex_%BUFFERSIZE] = packet;

    ++audioIndex_;
  }
}

uint32_t StatisticsWindow::bitrate(std::vector<PacketInfo*>& packets, uint32_t index)
{
  if(index == 0)
    return 0;

  uint32_t currentTime = QDateTime::currentMSecsSinceEpoch();
  uint32_t timeInterval = 0;
  uint32_t bitrate = 0;
  uint32_t bitrateInterval = 2000;

  uint32_t i = index - 1;

  PacketInfo* p = packets[i%BUFFERSIZE];

  while(p && timeInterval < bitrateInterval)
  {
    bitrate += p->size;
    if(i != 0)
      --i;
    else
      i = BUFFERSIZE - 1;

    timeInterval = currentTime - p->timestamp;
    p = packets[i%BUFFERSIZE];
  }

  //qDebug() << "Bitrate:" << bitrate << "timeInterval:"  << timeInterval;
  if(timeInterval)
    return 8*bitrate/(timeInterval);

  return 0;
}

void StatisticsWindow::addSendPacket(uint16_t size)
{
  sendMutex_.lock();
  ++sendPacketCount_;
  transferredData_ += size;
  sendMutex_.unlock();
}

void StatisticsWindow::addReceivePacket(uint16_t size)
{
  receiveMutex_.lock();
  ++receivePacketCount_;
  receivedData_ += size;
  receiveMutex_.unlock();
}

void StatisticsWindow::updateBufferStatus(QString filter, uint16_t buffersize)
{
  bufferMutex_.lock();
  if(buffers_.find(filter) == buffers_.end() || buffers_[filter] != buffersize)
  {
    dirtyBuffers_ = true;
    buffers_[filter] = buffersize;
  }
  bufferMutex_.unlock();
}

void StatisticsWindow::packetDropped()
{
  ++packetsDropped_;
}

void StatisticsWindow::paintEvent(QPaintEvent *event)
{
  if(videoIndex_%15 == 0)
  {
    lastVideoBitrate_ = bitrate(videoPackets_, videoIndex_);
    ui_->video_bitrate_value->setText
      ( QString::number(lastVideoBitrate_) + " kbit/s" );

    uint index = 0;
    for(Delays d : delays_)
    {
      ui_->participantTable->setItem(index, 2, new QTableWidgetItem( QString::number(d.audio) + " ms"));
      ui_->participantTable->setItem(index, 3, new QTableWidgetItem( QString::number(d.video) + " ms"));
      ++index;
    }
  }

  if(audioIndex_%20 == 0)
  {
    lastAudioBitrate_ = bitrate(audioPackets_, audioIndex_);
    ui_->audio_bitrate_value->setText
      ( QString::number(lastAudioBitrate_) + " kbit/s" );
  }

  ui_->packets_sent_value->setText( QString::number(sendPacketCount_));
  ui_->data_sent_value->setText( QString::number(transferredData_));
  ui_->packets_received_value->setText( QString::number(receivePacketCount_));
  ui_->data_received_value->setText( QString::number(receivedData_));
  ui_->packets_skipped_value->setText(QString::number(packetsDropped_));

  if(dirtyBuffers_)
  {
    bufferMutex_.lock();
    ui_->buffer_sizes_value->setText( QString::number(totalBuffers()));
    dirtyBuffers_ = false;
    bufferMutex_.unlock();
  }
}

uint32_t StatisticsWindow::totalBuffers()
{
  uint32_t total = 0;
  for(auto& it : buffers_)
  {
    total += it.second;
  }
  return total;
}
<commit_msg>Minor text fix.<commit_after>#include "statisticswindow.h"
#include "ui_statisticswindow.h"

#include <QCloseEvent>
#include <QDateTime>
#include <QDebug>

const int BUFFERSIZE = 65536;

StatisticsWindow::StatisticsWindow(QWidget *parent) :
QDialog(parent),
StatisticsInterface(),
ui_(new Ui::StatisticsWindow),
  framerate_(0),
  videoIndex_(0), // ringbuffer index
  videoPackets_(BUFFERSIZE,0), // ringbuffer
  audioIndex_(0), // ringbuffer index
  audioPackets_(BUFFERSIZE,0), // ringbuffer
  sendPacketCount_(0),
  transferredData_(0),
  receivePacketCount_(0),
  receivedData_(0),
  packetsDropped_(0),
  lastVideoBitrate_(0),
  lastAudioBitrate_(0)
{
  ui_->setupUi(this);
  ui_->participantTable->setColumnCount(4); // more columns can be added later
  ui_->participantTable->setHorizontalHeaderItem(0, new QTableWidgetItem(QString("IP")));
  ui_->participantTable->setHorizontalHeaderItem(1, new QTableWidgetItem(QString("Port")));
  ui_->participantTable->setHorizontalHeaderItem(2, new QTableWidgetItem(QString("Audio delay")));
  ui_->participantTable->setHorizontalHeaderItem(3, new QTableWidgetItem(QString("Video delay")));
}

StatisticsWindow::~StatisticsWindow()
{
  delete ui_;
}

void StatisticsWindow::closeEvent(QCloseEvent *event)
{
  accept();
}

void StatisticsWindow::addNextInterface(StatisticsInterface* next)
{}

void StatisticsWindow::videoInfo(double framerate, QSize resolution)
{
  framerate_ = framerate;
  ui_->framerate_value->setText( QString::number(framerate)+" fps");
  ui_->resolution_value->setText( QString::number(resolution.width()) + "x"
                          + QString::number(resolution.height()));
}

void StatisticsWindow::audioInfo(uint32_t sampleRate, uint16_t channelCount)
{
  //ui_->a_framerate_value->setText(QString::number(framerate)+"fps");
  ui_->channels_value->setText(QString::number(channelCount));
  ui_->sample_rate_value->setText(QString::number(sampleRate) + " Hz");
}

void StatisticsWindow::addParticipant(QString ip, QString port)
{
  ui_->participantTable->insertRow(ui_->participantTable->rowCount());
  // add cells to table
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 0, new QTableWidgetItem(ip));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 1, new QTableWidgetItem(port));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 2, new QTableWidgetItem("- ms"));
  ui_->participantTable->setItem(ui_->participantTable->rowCount() -1, 3, new QTableWidgetItem("- ms"));

  delays_.push_back({0,0});

}

void StatisticsWindow::sendDelay(QString type, uint32_t delay)
{
  if(type == "video" || type == "Video")
  {
    sendMutex_.lock();
    ui_->encode_delay_value->setText( QString::number(delay) + " ms." );
    sendMutex_.unlock();
  }
  else if(type == "audio" || type == "Audio")
  {
    sendMutex_.lock();
    ui_->audio_delay_value->setText( QString::number(delay) + " ms." );
    sendMutex_.unlock();
  }
}

void StatisticsWindow::receiveDelay(uint32_t peer, QString type, int32_t delay)
{
  if(type == "video" || type == "Video")
  {
    delays_.at(peer).video = delay;
    //ui_->participantTable->setItem(peer, 3, new QTableWidgetItem( QString::number(delay) + " ms"));
  }
  else if(type == "audio" || type == "Audio")
  {
    delays_.at(peer).audio = delay;
    //ui_->participantTable->setItem(peer, 2, new QTableWidgetItem( QString::number(delay) + " ms"));
  }
}

void StatisticsWindow::addEncodedPacket(QString type, uint16_t size)
{
  PacketInfo *packet = new PacketInfo{QDateTime::currentMSecsSinceEpoch(), size};

  if(type == "video" || type == "Video")
  {
    if(videoPackets_[videoIndex_%BUFFERSIZE])
    {
      delete videoPackets_.at(videoIndex_%BUFFERSIZE);
    }

    videoPackets_[videoIndex_%BUFFERSIZE] = packet;

    ++videoIndex_;
  }
  else if(type == "audio" || type == "Audio")
  {
    if(audioPackets_[audioIndex_%BUFFERSIZE])
    {
      delete audioPackets_.at(audioIndex_%BUFFERSIZE);
    }

    audioPackets_[audioIndex_%BUFFERSIZE] = packet;

    ++audioIndex_;
  }
}

uint32_t StatisticsWindow::bitrate(std::vector<PacketInfo*>& packets, uint32_t index)
{
  if(index == 0)
    return 0;

  uint32_t currentTime = QDateTime::currentMSecsSinceEpoch();
  uint32_t timeInterval = 0;
  uint32_t bitrate = 0;
  uint32_t bitrateInterval = 2000;

  uint32_t i = index - 1;

  PacketInfo* p = packets[i%BUFFERSIZE];

  while(p && timeInterval < bitrateInterval)
  {
    bitrate += p->size;
    if(i != 0)
      --i;
    else
      i = BUFFERSIZE - 1;

    timeInterval = currentTime - p->timestamp;
    p = packets[i%BUFFERSIZE];
  }

  //qDebug() << "Bitrate:" << bitrate << "timeInterval:"  << timeInterval;
  if(timeInterval)
    return 8*bitrate/(timeInterval);

  return 0;
}

void StatisticsWindow::addSendPacket(uint16_t size)
{
  sendMutex_.lock();
  ++sendPacketCount_;
  transferredData_ += size;
  sendMutex_.unlock();
}

void StatisticsWindow::addReceivePacket(uint16_t size)
{
  receiveMutex_.lock();
  ++receivePacketCount_;
  receivedData_ += size;
  receiveMutex_.unlock();
}

void StatisticsWindow::updateBufferStatus(QString filter, uint16_t buffersize)
{
  bufferMutex_.lock();
  if(buffers_.find(filter) == buffers_.end() || buffers_[filter] != buffersize)
  {
    dirtyBuffers_ = true;
    buffers_[filter] = buffersize;
  }
  bufferMutex_.unlock();
}

void StatisticsWindow::packetDropped()
{
  ++packetsDropped_;
}

void StatisticsWindow::paintEvent(QPaintEvent *event)
{
  if(videoIndex_%15 == 0)
  {
    lastVideoBitrate_ = bitrate(videoPackets_, videoIndex_);
    ui_->video_bitrate_value->setText
      ( QString::number(lastVideoBitrate_) + " kbit/s" );

    uint index = 0;
    for(Delays d : delays_)
    {
      ui_->participantTable->setItem(index, 2, new QTableWidgetItem( QString::number(d.audio) + " ms"));
      ui_->participantTable->setItem(index, 3, new QTableWidgetItem( QString::number(d.video) + " ms"));
      ++index;
    }
  }

  if(audioIndex_%20 == 0)
  {
    lastAudioBitrate_ = bitrate(audioPackets_, audioIndex_);
    ui_->audio_bitrate_value->setText
      ( QString::number(lastAudioBitrate_) + " kbit/s" );
  }

  ui_->packets_sent_value->setText( QString::number(sendPacketCount_));
  ui_->data_sent_value->setText( QString::number(transferredData_));
  ui_->packets_received_value->setText( QString::number(receivePacketCount_));
  ui_->data_received_value->setText( QString::number(receivedData_));
  ui_->packets_skipped_value->setText(QString::number(packetsDropped_));

  if(dirtyBuffers_)
  {
    bufferMutex_.lock();
    ui_->buffer_sizes_value->setText( QString::number(totalBuffers()));
    dirtyBuffers_ = false;
    bufferMutex_.unlock();
  }
}

uint32_t StatisticsWindow::totalBuffers()
{
  uint32_t total = 0;
  for(auto& it : buffers_)
  {
    total += it.second;
  }
  return total;
}
<|endoftext|>