<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mrs00.C
/// @brief Run and manage the DDR4 MRS00 loading
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <mss.H>
#include <lib/dimm/ddr4/mrs_load_ddr4.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_DIMM;

using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

namespace ddr4
{

///
/// @brief mrs0_data ctor
/// @param[in] a fapi2::TARGET_TYPE_DIMM target
/// @param[out] fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
mrs00_data::mrs00_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc ):
    iv_burst_length(0),
    iv_read_burst_type(0),
    iv_dll_reset(0),
    iv_test_mode(0),
    iv_write_recovery(0),
    iv_cas_latency(0)
{
    FAPI_TRY( mss::eff_dram_bl(i_target, iv_burst_length) );
    FAPI_TRY( mss::eff_dram_rbt(i_target, iv_read_burst_type) );
    FAPI_TRY( mss::eff_dram_cl(i_target, iv_cas_latency) );
    FAPI_TRY( mss::eff_dram_dll_reset(i_target, iv_dll_reset) );
    FAPI_TRY( mss::eff_dram_tm(i_target, iv_test_mode) );
    FAPI_TRY( mss::eff_dram_twr(i_target, iv_write_recovery) );

    FAPI_INF("MR0 Attributes: BL: 0x%x, RBT: 0x%x, CL: 0x%x, TM: 0x%x, DLL_RESET: 0x%x, WR: 0x%x",
             iv_burst_length, iv_read_burst_type, iv_cas_latency, iv_test_mode, iv_dll_reset, iv_write_recovery);

    o_rc = fapi2::FAPI2_RC_SUCCESS;
    return;

fapi_try_exit:
    o_rc = fapi2::current_err;
    FAPI_ERR("unable to get attributes for mrs0");
    return;
}

///
/// @brief Configure the ARR0 of the CCS instruction for mrs00
/// @param[in] i_target a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in,out] io_inst the instruction to fixup
/// @param[in] i_rank the rank in question
/// @return FAPI2_RC_SUCCESS iff OK
///
fapi2::ReturnCode mrs00(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
                        ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
                        const uint64_t i_rank)
{
    // Check to make sure our ctor worked ok
    mrs00_data l_data( i_target, fapi2::current_err );
    FAPI_TRY( fapi2::current_err, "Unable to construct MRS00 data from attributes");
    FAPI_TRY( mrs00(i_target, l_data, io_inst, i_rank) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Configure the ARR0 of the CCS instruction for mrs00, data object as input
/// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
/// @param[in] i_data an mrs00_data object, filled in
/// @param[in,out] io_inst the instruction to fixup
/// @param[in] i_rank the rank in question
/// @return FAPI2_RC_SUCCESS iff OK
///
fapi2::ReturnCode mrs00(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                        const mrs00_data& i_data,
                        ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
                        const uint64_t i_rank)
{
    // Map from Write Recovery attribute value to bits in the MRS.
    // Bit 4 is A13, bits 5:7 are A11:A9
    constexpr uint64_t LOWEST_WR = 10;
    constexpr uint64_t WR_COUNT = 17;
    constexpr uint8_t wr_map[WR_COUNT] =
    {
        // 10        12         14         16         18         20         22         24         26
        0b0000, 0, 0b0001, 0, 0b0001, 0, 0b0011, 0, 0b0100, 0, 0b0101, 0, 0b0111, 0, 0b0110, 0, 0b1000
    };

    // Map from the CAS Latency attribute to the bits in the MRS
    constexpr uint64_t LOWEST_CL = 9;
    constexpr uint64_t CL_COUNT = 25;
    constexpr uint8_t cl_map[CL_COUNT] =
    {
        // 9        10       11       12       13       14       15       16
        0b00000, 0b00001, 0b00010, 0b00011, 0b00100, 0b00101, 0b00110, 0b00111,
        // 17,      18       19       20       21       22       23       24
        0b01101, 0b01000, 0b01110, 0b01001, 0b01111, 0b01010, 0b01100, 0b01011,
        // 25       26       27       28       29       30       31       32       33
        0b10000, 0b10001, 0b10010, 0b10011, 0b10100, 0b10101, 0b10110, 0b10111, 0b11000
    };

    fapi2::buffer<uint8_t> l_cl;
    fapi2::buffer<uint8_t> l_wr;

    FAPI_ASSERT((i_data.iv_write_recovery >= LOWEST_WR) && (i_data.iv_write_recovery < (LOWEST_WR + WR_COUNT)),
                fapi2::MSS_BAD_MR_PARAMETER()
                .set_MR_NUMBER(0)
                .set_PARAMETER(WRITE_RECOVERY)
                .set_PARAMETER_VALUE(i_data.iv_write_recovery)
                .set_DIMM_IN_ERROR(i_target),
                "Bad value for Write Recovery: %d (%s)", i_data.iv_write_recovery, mss::c_str(i_target));

    FAPI_ASSERT((i_data.iv_cas_latency >= LOWEST_CL) && (i_data.iv_cas_latency < (LOWEST_CL + CL_COUNT)),
                fapi2::MSS_BAD_MR_PARAMETER()
                .set_MR_NUMBER(0)
                .set_PARAMETER(CAS_LATENCY)
                .set_PARAMETER_VALUE(i_data.iv_cas_latency)
                .set_DIMM_IN_ERROR(i_target),
                "Bad value for CAS Latency: %d (%s)", i_data.iv_cas_latency, mss::c_str(i_target));

    io_inst.arr0.insertFromRight<A0, 2>(i_data.iv_burst_length);
    io_inst.arr0.writeBit<A3>(i_data.iv_read_burst_type);
    io_inst.arr0.writeBit<A7>(i_data.iv_test_mode);
    io_inst.arr0.writeBit<A8>(i_data.iv_dll_reset);

    // CAS Latency takes a little effort - the bits aren't contiguous
    l_cl = cl_map[i_data.iv_cas_latency - LOWEST_CL];
    io_inst.arr0.writeBit<A12>(l_cl.getBit<3>());
    io_inst.arr0.writeBit<A6>(l_cl.getBit<4>());
    io_inst.arr0.writeBit<A5>(l_cl.getBit<5>());
    io_inst.arr0.writeBit<A4>(l_cl.getBit<6>());
    io_inst.arr0.writeBit<A2>(l_cl.getBit<7>());

    // Write Recovery/Read to Precharge is not contiguous either.
    l_wr = wr_map[i_data.iv_write_recovery - LOWEST_WR];
    io_inst.arr0.writeBit<A13>(l_wr.getBit<4>());
    io_inst.arr0.writeBit<A11>(l_wr.getBit<5>());
    io_inst.arr0.writeBit<A10>(l_wr.getBit<6>());
    io_inst.arr0.writeBit<A9>(l_wr.getBit<7>());

    FAPI_INF("MR0: 0x%016llx", uint64_t(io_inst.arr0));

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Given a CCS instruction which contains address bits with an encoded MRS0,
/// decode and trace the contents
/// @param[in] i_inst the CCS instruction
/// @param[in] i_rank ths rank in question
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode mrs00_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
                               const uint64_t i_rank)
{
    static const uint8_t wr_map[9] = { 10, 12, 14, 16, 18, 20, 24, 22, 26 };

    uint8_t l_burst_length = 0;
    uint8_t l_read_burst_type = 0;
    uint8_t l_dll_reset = 0;
    uint8_t l_test_mode = 0;

    fapi2::buffer<uint8_t> l_wr_index;
    fapi2::buffer<uint8_t> l_cas_latency;

    i_inst.arr0.extractToRight<A0, 2>(l_burst_length);
    l_read_burst_type = i_inst.arr0.getBit<A3>();
    l_test_mode = i_inst.arr0.getBit<A7>();
    l_dll_reset = i_inst.arr0.getBit<A8>();

    // CAS Latency takes a little effort - the bits aren't contiguous
    l_cas_latency.writeBit<3>(i_inst.arr0.getBit<A12>());
    l_cas_latency.writeBit<4>(i_inst.arr0.getBit<A6>());
    l_cas_latency.writeBit<5>(i_inst.arr0.getBit<A5>());
    l_cas_latency.writeBit<6>(i_inst.arr0.getBit<A4>());
    l_cas_latency.writeBit<7>(i_inst.arr0.getBit<A2>());

    // Write Recovery/Read to Precharge is not contiguous either.
    l_wr_index.writeBit<4>(i_inst.arr0.getBit<A13>());
    l_wr_index.writeBit<5>(i_inst.arr0.getBit<A11>());
    l_wr_index.writeBit<6>(i_inst.arr0.getBit<A10>());
    l_wr_index.writeBit<7>(i_inst.arr0.getBit<A9>());

    FAPI_INF("MR0 Decode BL: 0x%x, RBT: 0x%x, CL: 0x%x, TM: 0x%x, DLL_RESET: 0x%x, WR: (0x%x)0x%x",
             l_burst_length, l_read_burst_type, uint8_t(l_cas_latency), l_test_mode, l_dll_reset,
             wr_map[uint8_t(l_wr_index)], uint8_t(l_wr_index));

    return FAPI2_RC_SUCCESS;
}

fapi2::ReturnCode (*mrs00_data::make_ccs_instruction)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
        const mrs00_data& i_data,
        ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
        const uint64_t i_rank) = &mrs00;

fapi2::ReturnCode (*mrs00_data::decode)(const ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& i_inst,
                                        const uint64_t i_rank) = &mrs00_decode;

} // ns ddr4

} // ns mss
<commit_msg>Adding defaults for DRAM dll_reset and dll_enable<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/ddr4/mrs00.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mrs00.C
/// @brief Run and manage the DDR4 MRS00 loading
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <mss.H>
#include <lib/dimm/ddr4/mrs_load_ddr4.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_DIMM;

using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

namespace ddr4
{

///
/// @brief mrs0_data ctor
/// @param[in] a fapi2::TARGET_TYPE_DIMM target
/// @param[out] fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
mrs00_data::mrs00_data( const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target, fapi2::ReturnCode& o_rc ):
    iv_burst_length(0),
    iv_read_burst_type(0),
    iv_dll_reset(fapi2::ENUM_ATTR_EFF_DRAM_DLL_RESET_NO),
    iv_test_mode(0),
    iv_write_recovery(0),
    iv_cas_latency(0)
{
    FAPI_TRY( mss::eff_dram_bl(i_target, iv_burst_length) );
    FAPI_TRY( mss::eff_dram_rbt(i_target, iv_read_burst_type) );
    FAPI_TRY( mss::eff_dram_cl(i_target, iv_cas_latency) );
    FAPI_TRY( mss::eff_dram_dll_reset(i_target, iv_dll_reset) );
    FAPI_TRY( mss::eff_dram_tm(i_target, iv_test_mode) );
    FAPI_TRY( mss::eff_dram_twr(i_target, iv_write_recovery) );

    FAPI_INF("MR0 Attributes: BL: 0x%x, RBT: 0x%x, CL: 0x%x, TM: 0x%x, DLL_RESET: 0x%x, WR: 0x%x",
             iv_burst_length, iv_read_burst_type, iv_cas_latency, iv_test_mode, iv_dll_reset, iv_write_recovery);

    o_rc = fapi2::FAPI2_RC_SUCCESS;
    return;

fapi_try_exit:
    o_rc = fapi2::current_err;
    FAPI_ERR("unable to get attributes for mrs0");
    return;
}

///
/// @brief Configure the ARR0 of the CCS instruction for mrs00
/// @param[in] i_target a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in,out] io_inst the instruction to fixup
/// @param[in] i_rank the rank in question
/// @return FAPI2_RC_SUCCESS iff OK
///
fapi2::ReturnCode mrs00(const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
                        ccs::instruction_t<TARGET_TYPE_MCBIST>& io_inst,
                        const uint64_t i_rank)
{
    // Check to make sure our ctor worked ok
    mrs00_data l_data( i_target, fapi2::current_err );
    FAPI_TRY( fapi2::current_err, "Unable to construct MRS00 data from attributes");
    FAPI_TRY( mrs00(i_target, l_data, io_inst, i_rank) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Configure the ARR0 of the CCS instruction for mrs00, data object as input
/// @param[in] i_target a fapi2::Target<fapi2::TARGET_TYPE_DIMM>
/// @param[in] i_data an mrs00_data object, filled in
/// @param[in,out] io_inst the instruction to fixup
/// @param[in] i_rank the rank in question
/// @return FAPI2_RC_SUCCESS iff OK
///
fapi2::ReturnCode mrs00(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                        const mrs00_data& i_data,
                        ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
                        const uint64_t i_rank)
{
    // Map from Write Recovery attribute value to bits in the MRS.
    // Bit 4 is A13, bits 5:7 are A11:A9
    constexpr uint64_t LOWEST_WR = 10;
    constexpr uint64_t WR_COUNT = 17;
    constexpr uint8_t wr_map[WR_COUNT] =
    {
        // 10        12         14         16         18         20         22         24         26
        0b0000, 0, 0b0001, 0, 0b0001, 0, 0b0011, 0, 0b0100, 0, 0b0101, 0, 0b0111, 0, 0b0110, 0, 0b1000
    };

    // Map from the CAS Latency attribute to the bits in the MRS
    constexpr uint64_t LOWEST_CL = 9;
    constexpr uint64_t CL_COUNT = 25;
    constexpr uint8_t cl_map[CL_COUNT] =
    {
        // 9        10       11       12       13       14       15       16
        0b00000, 0b00001, 0b00010, 0b00011, 0b00100, 0b00101, 0b00110, 0b00111,
        // 17,      18       19       20       21       22       23       24
        0b01101, 0b01000, 0b01110, 0b01001, 0b01111, 0b01010, 0b01100, 0b01011,
        // 25       26       27       28       29       30       31       32       33
        0b10000, 0b10001, 0b10010, 0b10011, 0b10100, 0b10101, 0b10110, 0b10111, 0b11000
    };

    fapi2::buffer<uint8_t> l_cl;
    fapi2::buffer<uint8_t> l_wr;

    FAPI_ASSERT((i_data.iv_write_recovery >= LOWEST_WR) && (i_data.iv_write_recovery < (LOWEST_WR + WR_COUNT)),
                fapi2::MSS_BAD_MR_PARAMETER()
                .set_MR_NUMBER(0)
                .set_PARAMETER(WRITE_RECOVERY)
                .set_PARAMETER_VALUE(i_data.iv_write_recovery)
                .set_DIMM_IN_ERROR(i_target),
                "Bad value for Write Recovery: %d (%s)", i_data.iv_write_recovery, mss::c_str(i_target));

    FAPI_ASSERT((i_data.iv_cas_latency >= LOWEST_CL) && (i_data.iv_cas_latency < (LOWEST_CL + CL_COUNT)),
                fapi2::MSS_BAD_MR_PARAMETER()
                .set_MR_NUMBER(0)
                .set_PARAMETER(CAS_LATENCY)
                .set_PARAMETER_VALUE(i_data.iv_cas_latency)
                .set_DIMM_IN_ERROR(i_target),
                "Bad value for CAS Latency: %d (%s)", i_data.iv_cas_latency, mss::c_str(i_target));

    io_inst.arr0.insertFromRight<A0, 2>(i_data.iv_burst_length);
    io_inst.arr0.writeBit<A3>(i_data.iv_read_burst_type);
    io_inst.arr0.writeBit<A7>(i_data.iv_test_mode);
    io_inst.arr0.writeBit<A8>(i_data.iv_dll_reset);

    // CAS Latency takes a little effort - the bits aren't contiguous
    l_cl = cl_map[i_data.iv_cas_latency - LOWEST_CL];
    io_inst.arr0.writeBit<A12>(l_cl.getBit<3>());
    io_inst.arr0.writeBit<A6>(l_cl.getBit<4>());
    io_inst.arr0.writeBit<A5>(l_cl.getBit<5>());
    io_inst.arr0.writeBit<A4>(l_cl.getBit<6>());
    io_inst.arr0.writeBit<A2>(l_cl.getBit<7>());

    // Write Recovery/Read to Precharge is not contiguous either.
    l_wr = wr_map[i_data.iv_write_recovery - LOWEST_WR];
    io_inst.arr0.writeBit<A13>(l_wr.getBit<4>());
    io_inst.arr0.writeBit<A11>(l_wr.getBit<5>());
    io_inst.arr0.writeBit<A10>(l_wr.getBit<6>());
    io_inst.arr0.writeBit<A9>(l_wr.getBit<7>());

    FAPI_INF("MR0: 0x%016llx", uint64_t(io_inst.arr0));

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Given a CCS instruction which contains address bits with an encoded MRS0,
/// decode and trace the contents
/// @param[in] i_inst the CCS instruction
/// @param[in] i_rank ths rank in question
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode mrs00_decode(const ccs::instruction_t<TARGET_TYPE_MCBIST>& i_inst,
                               const uint64_t i_rank)
{
    static const uint8_t wr_map[9] = { 10, 12, 14, 16, 18, 20, 24, 22, 26 };

    uint8_t l_burst_length = 0;
    uint8_t l_read_burst_type = 0;
    uint8_t l_dll_reset = 0;
    uint8_t l_test_mode = 0;

    fapi2::buffer<uint8_t> l_wr_index;
    fapi2::buffer<uint8_t> l_cas_latency;

    i_inst.arr0.extractToRight<A0, 2>(l_burst_length);
    l_read_burst_type = i_inst.arr0.getBit<A3>();
    l_test_mode = i_inst.arr0.getBit<A7>();
    l_dll_reset = i_inst.arr0.getBit<A8>();

    // CAS Latency takes a little effort - the bits aren't contiguous
    l_cas_latency.writeBit<3>(i_inst.arr0.getBit<A12>());
    l_cas_latency.writeBit<4>(i_inst.arr0.getBit<A6>());
    l_cas_latency.writeBit<5>(i_inst.arr0.getBit<A5>());
    l_cas_latency.writeBit<6>(i_inst.arr0.getBit<A4>());
    l_cas_latency.writeBit<7>(i_inst.arr0.getBit<A2>());

    // Write Recovery/Read to Precharge is not contiguous either.
    l_wr_index.writeBit<4>(i_inst.arr0.getBit<A13>());
    l_wr_index.writeBit<5>(i_inst.arr0.getBit<A11>());
    l_wr_index.writeBit<6>(i_inst.arr0.getBit<A10>());
    l_wr_index.writeBit<7>(i_inst.arr0.getBit<A9>());

    FAPI_INF("MR0 Decode BL: 0x%x, RBT: 0x%x, CL: 0x%x, TM: 0x%x, DLL_RESET: 0x%x, WR: (0x%x)0x%x",
             l_burst_length, l_read_burst_type, uint8_t(l_cas_latency), l_test_mode, l_dll_reset,
             wr_map[uint8_t(l_wr_index)], uint8_t(l_wr_index));

    return FAPI2_RC_SUCCESS;
}

fapi2::ReturnCode (*mrs00_data::make_ccs_instruction)(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
        const mrs00_data& i_data,
        ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& io_inst,
        const uint64_t i_rank) = &mrs00;

fapi2::ReturnCode (*mrs00_data::decode)(const ccs::instruction_t<fapi2::TARGET_TYPE_MCBIST>& i_inst,
                                        const uint64_t i_rank) = &mrs00_decode;

} // ns ddr4

} // ns mss
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkCanvas.h"
#include "SkPath.h"

#define STROKE_WIDTH    SkIntToScalar(10)

typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);

static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    canvas->drawRect(r, p);
}

static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    SkRect  rect;
    SkPath  path;

    rect = r;
    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
    path.addRect(rect);
    rect = r;
    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);

    path.addRect(rect);
    path.setFillType(SkPath::kEvenOdd_FillType);

    canvas->drawPath(path, p);
}

static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    SkRect  rect;
    SkPath  path;

    rect = r;
    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
    path.addRect(rect);
    rect = r;
    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);

    rect.offset(7, -7);

    path.addRect(rect);
    path.setFillType(SkPath::kEvenOdd_FillType);

    canvas->drawPath(path, p);
}

#include "SkGradientShader.h"

typedef void (*PaintProc)(SkPaint*, SkScalar width);

static const char* gBlurStyle2Name[] = {
    "normal",
    "solid",
    "outer",
    "inner"
};

class BlurRectGM : public skiagm::GM {
    SkAutoTUnref<SkMaskFilter> fMaskFilter;
    SkString  fName;
    PaintProc fPProc;
    SkAlpha   fAlpha;
public:
    BlurRectGM(const char name[], PaintProc pproc, U8CPU alpha,
               SkBlurMaskFilter::BlurStyle bs) :
        fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
                                       SkBlurMaskFilter::kHighQuality_BlurFlag))
        , fName(name)
        , fPProc(pproc)
        , fAlpha(SkToU8(alpha))
    {
        fName.appendf("_%s", gBlurStyle2Name[bs]);
    }

protected:
    virtual SkString onShortName() {
        return fName;
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {
        canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);

        SkRect  r = { 0, 0, 250, 120 };

        SkPaint paint;
        paint.setMaskFilter(fMaskFilter);
        if (fPProc) {
            fPProc(&paint, r.width());
        }
        paint.setAlpha(fAlpha);

        static const Proc procs[] = {
            fill_rect, draw_donut, draw_donut_skewed
        };

        this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
        canvas->translate(r.width() * 4/3, 0);
        this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
    }

    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }

private:
    void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
                   bool doClip, const Proc procs[], size_t procsCount) {
        SkAutoCanvasRestore acr(canvas, true);
        for (size_t i = 0; i < procsCount; ++i) {
            if (doClip) {
                SkRect clipRect(r);
                clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
                canvas->save();
                canvas->clipRect(r);
            }
            procs[i](canvas, r, paint);
            if (doClip) {
                canvas->restore();
            }
            canvas->translate(0, r.height() * 4/3);
        }
    }

    typedef GM INHERITED;
};

class BlurRectCompareGM : public skiagm::GM {
    SkString  fName;
    unsigned int fRectWidth, fRectHeight;
    SkScalar fRadius;
public:
    BlurRectCompareGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, float radius)
        : fName(name)
        , fRectWidth(rectWidth)
        , fRectHeight(rectHeight)
        , fRadius(radius)
    {}

  int width() const { return fRectWidth; }
  int height() const { return fRectHeight; }
  SkScalar radius() const { return fRadius; }

protected:
    virtual SkString onShortName() {
        return fName;
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void makeMask(SkMask *m, const SkRect&) = 0;

    virtual void onDraw(SkCanvas* canvas) {
      SkRect r;
      r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));

      SkMask mask;

      this->makeMask(&mask, r);
      SkAutoMaskFreeImage amfi(mask.fImage);

      SkBitmap bm;
      bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height());
      bm.setPixels(mask.fImage);
      canvas->drawBitmap(bm, 50, 50, NULL);
    }

    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }

private:
    typedef GM INHERITED;
};

class BlurRectFastGM: public BlurRectCompareGM {
public:
    BlurRectFastGM(const char name[], unsigned int rect_width,
                   unsigned int rect_height, float blur_radius) :
        BlurRectCompareGM(name, rect_width, rect_height, blur_radius) {}
protected:
    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
        SkBlurMask::BlurRect(m, r, radius(), SkBlurMask::kNormal_Style,
                             SkBlurMask::kHigh_Quality );
    }
};

class BlurRectSlowGM: public BlurRectCompareGM {
public:
  BlurRectSlowGM(const char name[], unsigned int rect_width, unsigned int rect_height, float blur_radius) :
    BlurRectCompareGM( name, rect_width, rect_height, blur_radius ) {}
protected:
    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
        SkMask src;
        r.roundOut(&src.fBounds);
        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
        src.fFormat = SkMask::kA8_Format;
        src.fRowBytes = src.fBounds.width();
        src.fImage = SkMask::AllocImage( src.computeTotalImageSize() );
        SkAutoMaskFreeImage amfi(src.fImage);

        memset(src.fImage, 0xff, src.computeTotalImageSize());

        SkBlurMask::BlurSeparable(m, src, radius()/2, SkBlurMask::kNormal_Style, SkBlurMask::kHigh_Quality);
    }
};

//////////////////////////////////////////////////////////////////////////////

DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);)

#if 0   // disable while we debug an rtree failure
DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_10", 100, 100, 10);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_2", 100, 100, 2);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_10_10_100", 10, 10, 100);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_10_100_10", 10, 100, 10);)
#endif

DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_10", 100, 100, 10);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_2", 100, 100, 2);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_10_100", 10, 10, 100);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_100_10", 10, 100, 10);)
<commit_msg>Re-enbling blurrect gm test wich no longer fails with rtree/tileGrid Some re-baselining may be necessary since the existing ones may be out of date.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkCanvas.h"
#include "SkPath.h"

#define STROKE_WIDTH    SkIntToScalar(10)

typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);

static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    canvas->drawRect(r, p);
}

static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    SkRect  rect;
    SkPath  path;

    rect = r;
    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
    path.addRect(rect);
    rect = r;
    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);

    path.addRect(rect);
    path.setFillType(SkPath::kEvenOdd_FillType);

    canvas->drawPath(path, p);
}

static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
    SkRect  rect;
    SkPath  path;

    rect = r;
    rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
    path.addRect(rect);
    rect = r;
    rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);

    rect.offset(7, -7);

    path.addRect(rect);
    path.setFillType(SkPath::kEvenOdd_FillType);

    canvas->drawPath(path, p);
}

#include "SkGradientShader.h"

typedef void (*PaintProc)(SkPaint*, SkScalar width);

static const char* gBlurStyle2Name[] = {
    "normal",
    "solid",
    "outer",
    "inner"
};

class BlurRectGM : public skiagm::GM {
    SkAutoTUnref<SkMaskFilter> fMaskFilter;
    SkString  fName;
    PaintProc fPProc;
    SkAlpha   fAlpha;
public:
    BlurRectGM(const char name[], PaintProc pproc, U8CPU alpha,
               SkBlurMaskFilter::BlurStyle bs) :
        fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
                                       SkBlurMaskFilter::kHighQuality_BlurFlag))
        , fName(name)
        , fPProc(pproc)
        , fAlpha(SkToU8(alpha))
    {
        fName.appendf("_%s", gBlurStyle2Name[bs]);
    }

protected:
    virtual SkString onShortName() {
        return fName;
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void onDraw(SkCanvas* canvas) {
        canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);

        SkRect  r = { 0, 0, 250, 120 };

        SkPaint paint;
        paint.setMaskFilter(fMaskFilter);
        if (fPProc) {
            fPProc(&paint, r.width());
        }
        paint.setAlpha(fAlpha);

        static const Proc procs[] = {
            fill_rect, draw_donut, draw_donut_skewed
        };

        this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
        canvas->translate(r.width() * 4/3, 0);
        this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
    }

    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }

private:
    void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
                   bool doClip, const Proc procs[], size_t procsCount) {
        SkAutoCanvasRestore acr(canvas, true);
        for (size_t i = 0; i < procsCount; ++i) {
            if (doClip) {
                SkRect clipRect(r);
                clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
                canvas->save();
                canvas->clipRect(r);
            }
            procs[i](canvas, r, paint);
            if (doClip) {
                canvas->restore();
            }
            canvas->translate(0, r.height() * 4/3);
        }
    }

    typedef GM INHERITED;
};

class BlurRectCompareGM : public skiagm::GM {
    SkString  fName;
    unsigned int fRectWidth, fRectHeight;
    SkScalar fRadius;
public:
    BlurRectCompareGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, float radius)
        : fName(name)
        , fRectWidth(rectWidth)
        , fRectHeight(rectHeight)
        , fRadius(radius)
    {}

  int width() const { return fRectWidth; }
  int height() const { return fRectHeight; }
  SkScalar radius() const { return fRadius; }

protected:
    virtual SkString onShortName() {
        return fName;
    }

    virtual SkISize onISize() {
        return SkISize::Make(640, 480);
    }

    virtual void makeMask(SkMask *m, const SkRect&) = 0;

    virtual void onDraw(SkCanvas* canvas) {
      SkRect r;
      r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));

      SkMask mask;

      this->makeMask(&mask, r);
      SkAutoMaskFreeImage amfi(mask.fImage);

      SkBitmap bm;
      bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height());
      bm.setPixels(mask.fImage);
      canvas->drawBitmap(bm, 50, 50, NULL);
    }

    virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }

private:
    typedef GM INHERITED;
};

class BlurRectFastGM: public BlurRectCompareGM {
public:
    BlurRectFastGM(const char name[], unsigned int rect_width,
                   unsigned int rect_height, float blur_radius) :
        BlurRectCompareGM(name, rect_width, rect_height, blur_radius) {}
protected:
    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
        SkBlurMask::BlurRect(m, r, radius(), SkBlurMask::kNormal_Style,
                             SkBlurMask::kHigh_Quality );
    }
};

class BlurRectSlowGM: public BlurRectCompareGM {
public:
  BlurRectSlowGM(const char name[], unsigned int rect_width, unsigned int rect_height, float blur_radius) :
    BlurRectCompareGM( name, rect_width, rect_height, blur_radius ) {}
protected:
    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
        SkMask src;
        r.roundOut(&src.fBounds);
        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
        src.fFormat = SkMask::kA8_Format;
        src.fRowBytes = src.fBounds.width();
        src.fImage = SkMask::AllocImage( src.computeTotalImageSize() );
        SkAutoMaskFreeImage amfi(src.fImage);

        memset(src.fImage, 0xff, src.computeTotalImageSize());

        SkBlurMask::BlurSeparable(m, src, radius()/2, SkBlurMask::kNormal_Style, SkBlurMask::kHigh_Quality);
    }
};

//////////////////////////////////////////////////////////////////////////////

DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kNormal_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kSolid_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);)
DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);)

DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_10", 100, 100, 10);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_2", 100, 100, 2);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_10_10_100", 10, 10, 100);)
DEF_GM(return new BlurRectFastGM("blurrect_fast_10_100_10", 10, 100, 10);)

DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_10", 100, 100, 10);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_2", 100, 100, 2);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_10_100", 10, 10, 100);)
DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_100_10", 10, 100, 10);)
<|endoftext|>


<commit_before>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_SHORT;
        }
};

template <>
struct DatatypeSpecialization<unsigned short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_USHORT;
        }
};

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

template <>
struct DatatypeSpecialization<long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULONG;
        }
};

template <>
struct DatatypeSpecialization<long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LLONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULLONG;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// string types, to be used mainly for attributes

template <>
struct DatatypeSpecialization<const char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

template <>
struct DatatypeSpecialization<char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

// XXX: for some unknown reason the following two functions segfault if
// H5T_VARIABLE is used.  The passed strings should still be null-terminated,
// so this is a bit worrisome.

template <std::size_t N>
struct DatatypeSpecialization<const char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

template <std::size_t N>
struct DatatypeSpecialization<char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

namespace internal
{
    template <typename Derived>
    H5::DataSpace create_dataspace (const Eigen::EigenBase<Derived> &mat)
    {
        const std::size_t dimensions_size = 2;
        const hsize_t dimensions[dimensions_size] = {
            static_cast<hsize_t>(mat.rows()),
            static_cast<hsize_t>(mat.cols())
        };
        return H5::DataSpace(dimensions_size, dimensions);
    }

    // I suspect there is a more optimal way to set up the hyperslab that would avoid
    // copying row by row, but I do not know what it is right now.
    template <typename Derived>
    void write_mat_by_rows(const Eigen::EigenBase<Derived> &mat,
        const H5::DataType * const datatype,
        H5::DataSet *dataset,
        const H5::DataSpace* dataspace)
    {
        Derived::Index mstride = mat.derived().outerStride();

        // slab params for the file data
        hsize_t fstride[2] = { 1, mat.cols() };
        hsize_t count[2] = { 1, 1 };
        hsize_t block[2] = { 1, mat.cols() };

        // slab params for the memory data
        hsize_t mdim[2] = { 1, mat.cols() };
        H5::DataSpace mspace(2, mdim);

        // write each row of mat as a slab
        for (int i = 0; i < mat.rows(); i++)
        {
            hsize_t start[2] = { i, 0 };
            dataspace->selectHyperslab(H5S_SELECT_SET, count, start, fstride, block);
            dataset->write(mat.derived().data() + i*mstride, *datatype, mspace, *dataspace);
        }
    }
}

template <typename T>
void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const T &value)
{
    const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
    H5::DataSpace dataspace(H5S_SCALAR);
    H5::Attribute att = h5obj.createAttribute(name, *datatype, dataspace);
    att.write(*datatype, &value);
}

template <>
inline void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const std::string &value)
{
    save_scalar_attribute(h5obj, name, value.c_str());
}

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::CommonFG &h5group, const std::string &name, const Eigen::EigenBase<Derived> &mat, const H5::DSetCreatPropList &plist=H5::DSetCreatPropList::DEFAULT)
{
    typedef typename Derived::Scalar Scalar;
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    H5::DataSet dataset = h5group.createDataSet(name, *datatype, dataspace, plist);

    bool written = false;  // flag will be true when the data has been written
    if (mat.derived().Flags & Eigen::RowMajor)
    {
        // the matrix is stored in a row major order; see if it is contiguous
        if (mat.derived().outerStride() == mat.cols())
        {
            // the stride between rows is the number of columns means there is no padding between
            // rows, so the data is contiguous and we can write the data directly from memory
            // without copying.
            dataset.write(mat.derived().data(), *datatype);
            written = true;
        }
        else if (mat.derived().innerStride() == 1)
        {
            // inner stride == 1 is a sanity check. Only matrices made with unconventional maps
            // would have inner stride != 1, and they will be handled below by first copying the
            // input matrix.

            // write the matrix by rows to the dataset using the dataspace made above
            internal::write_mat_by_rows(mat, datatype, &dataset, &dataspace);
            written = true;
        }
    }

    if (!written)
    {
        // data has not yet been written, so there is nothing else to try but copy the input
        // matrix to a row major matrix and write it.
        const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
        dataset.write(row_major_mat.data(), *datatype);
    }
}

template <typename Derived>
void save_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::Attribute dataset = h5obj.createAttribute(name, *datatype, dataspace);
    dataset.write(*datatype, row_major_mat.data());
}

namespace internal
{
    // H5::Attribute and H5::DataSet both have similar API's, and although they
    // share a common base class, the relevant methods are not virtual.  Worst
    // of all, they take their arguments in different orders!

    template <typename Scalar>
    inline void read_data (const H5::DataSet &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(data, datatype);
    }

    template <typename Scalar>
    inline void read_data (const H5::Attribute &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(datatype, data);
    }

    template <typename Derived, typename DataSet>
    void _load (const DataSet &dataset, const Eigen::DenseBase<Derived> &mat)
    {
        typedef typename Derived::Scalar Scalar;
        const H5::DataSpace dataspace = dataset.getSpace();
        const std::size_t ndims = dataspace.getSimpleExtentNdims();
        assert(ndims > 0);
        const std::size_t dimensions_size = 2;
        hsize_t dimensions[dimensions_size];
        dimensions[1] = 1; // in case it's 1D
        if (ndims > dimensions_size) {
            throw std::runtime_error("HDF5 array has too many dimensions.");
        }
        dataspace.getSimpleExtentDims(dimensions);
        const hsize_t rows = dimensions[0], cols = dimensions[1];
        const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
        Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
        bool written = false;
        if (mat.Flags & Eigen::RowMajor || dimensions[0] == 1 || dimensions[1] == 1)
        {
            // mat is already row major; resize it and read into it
            mat_.derived().resize(rows, cols);
            Derived::Index stride = mat_.derived().outerStride();
            if (stride == cols || (stride == rows && cols == 1))
            {
                // mat has natural stride, so read directly into its data block
                internal::read_data(dataset, mat_.derived().data(), *datatype);
                written = true;
            }
        }

        if (!written)
        {
            // input is col major or has unnatural stride; read into a temp and copy it
            Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> temp(rows, cols);
            internal::read_data(dataset, temp.data(), *datatype);
            mat_ = temp;
            written = true;
        }
    }
}

template <typename Derived>
void load (const H5::CommonFG &h5group, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::DataSet dataset = h5group.openDataSet(name);
    internal::_load(dataset, mat);
}

template <typename Derived>
void load_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::Attribute dataset = h5obj.openAttribute(name);
    internal::_load(dataset, mat);
}

} // namespace EigenHDF5

#endif
<commit_msg>write column major matrix using hyperslab<commit_after>#ifndef _EIGEN3_HDF5_HPP
#define _EIGEN3_HDF5_HPP

#include <cassert>
#include <complex>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>

//#include <hdf5.h>
#include <H5Cpp.h>
#include <Eigen/Dense>

namespace EigenHDF5
{

template <typename T>
struct DatatypeSpecialization;

// floating-point types

template <>
struct DatatypeSpecialization<float>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_FLOAT;
        }
};

template <>
struct DatatypeSpecialization<double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_DOUBLE;
        }
};

template <>
struct DatatypeSpecialization<long double>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LDOUBLE;
        }
};

// integer types

template <>
struct DatatypeSpecialization<short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_SHORT;
        }
};

template <>
struct DatatypeSpecialization<unsigned short>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_USHORT;
        }
};

template <>
struct DatatypeSpecialization<int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_INT;
        }
};

template <>
struct DatatypeSpecialization<unsigned int>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_UINT;
        }
};

template <>
struct DatatypeSpecialization<long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULONG;
        }
};

template <>
struct DatatypeSpecialization<long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_LLONG;
        }
};

template <>
struct DatatypeSpecialization<unsigned long long>
{
    static inline const H5::DataType * get (void)
        {
            return &H5::PredType::NATIVE_ULLONG;
        }
};

// complex types
//
// inspired by http://www.mail-archive.com/hdf-forum@hdfgroup.org/msg00759.html

template <typename T>
class ComplexH5Type : public H5::CompType
{
public:
    ComplexH5Type (void)
        : CompType(sizeof(std::complex<T>))
        {
            const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
            assert(datatype->getSize() == sizeof(T));
            // If we call the members "r" and "i", h5py interprets the
            // structure correctly as complex numbers.
            this->insertMember(std::string("r"), 0, *datatype);
            this->insertMember(std::string("i"), sizeof(T), *datatype);
            this->pack();
        }

    static const ComplexH5Type<T> * get_singleton (void)
        {
            // NOTE: constructing this could be a race condition
            static ComplexH5Type<T> singleton;
            return &singleton;
        }
};

template <typename T>
struct DatatypeSpecialization<std::complex<T> >
{
    static inline const H5::DataType * get (void)
        {
            return ComplexH5Type<T>::get_singleton();
        }
};

// string types, to be used mainly for attributes

template <>
struct DatatypeSpecialization<const char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

template <>
struct DatatypeSpecialization<char *>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, H5T_VARIABLE);
            return &strtype;
        }
};

// XXX: for some unknown reason the following two functions segfault if
// H5T_VARIABLE is used.  The passed strings should still be null-terminated,
// so this is a bit worrisome.

template <std::size_t N>
struct DatatypeSpecialization<const char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

template <std::size_t N>
struct DatatypeSpecialization<char [N]>
{
    static inline const H5::DataType * get (void)
        {
            static const H5::StrType strtype(0, N);
            return &strtype;
        }
};

namespace internal
{
    template <typename Derived>
    H5::DataSpace create_dataspace (const Eigen::EigenBase<Derived> &mat)
    {
        const std::size_t dimensions_size = 2;
        const hsize_t dimensions[dimensions_size] = {
            static_cast<hsize_t>(mat.rows()),
            static_cast<hsize_t>(mat.cols())
        };
        return H5::DataSpace(dimensions_size, dimensions);
    }

    // I suspect there is a more optimal way to set up the hyperslab that would avoid
    // copying row by row, but I do not know what it is right now.
    template <typename Derived>
    bool write_mat_by_rows(const Eigen::EigenBase<Derived> &mat,
        const H5::DataType * const datatype,
        H5::DataSet *dataset,
        const H5::DataSpace* dataspace)
    {
        Derived::Index mstride = mat.derived().outerStride();

        // slab params for the file data
        hsize_t fstride[2] = { 1, mat.cols() };
        hsize_t count[2] = { 1, 1 };
        hsize_t block[2] = { 1, mat.cols() };

        // slab params for the memory data
        hsize_t mdim[2] = { 1, mat.cols() };
        H5::DataSpace mspace(2, mdim);

        // write each row of mat as a slab
        for (int i = 0; i < mat.rows(); i++)
        {
            hsize_t start[2] = { i, 0 };
            dataspace->selectHyperslab(H5S_SELECT_SET, count, start, fstride, block);
            dataset->write(mat.derived().data() + i*mstride, *datatype, mspace, *dataspace);
        }
        return true;
    }

    template <typename Derived>
    bool write_col_mat(const Eigen::EigenBase<Derived> &mat,
        const H5::DataType * const datatype,
        H5::DataSet *dataset,
        const H5::DataSpace* dspace)
    {
        bool written = false;
        Derived::Index rows = mat.rows();
        Derived::Index cols = mat.cols();

        Derived::Index stride = mat.derived().outerStride();
        if (rows == stride)
        {
            // slab params for the file data
            hsize_t fstride[2] = { 1, 1 };
            hsize_t fcount[2] = { 1, 1 };
            hsize_t fblock[2] = { 1, cols };

            // slab params for the memory data
            hsize_t mdim[2] = { cols, rows };
            H5::DataSpace mspace(2, mdim);
            hsize_t mstride[2] = { rows, 1 };
            hsize_t mcount[2] = { 1, 1 };
            hsize_t mblock[2] = { cols, 1 };

            // write each row of mat as a slab
            for (int i = 0; i < rows; i++)
            {
                hsize_t fstart[2] = { i, 0 };
                hsize_t mstart[2] = { 0, i };
                dspace->selectHyperslab(H5S_SELECT_SET, fcount, fstart, fstride, fblock);
                mspace.selectHyperslab(H5S_SELECT_SET, mcount, mstart, mstride, mblock);
                dataset->write(mat.derived().data(), *datatype, mspace, *dspace);
            }
            written = true;
        }
        return written;
    }
}

template <typename T>
void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const T &value)
{
    const H5::DataType * const datatype = DatatypeSpecialization<T>::get();
    H5::DataSpace dataspace(H5S_SCALAR);
    H5::Attribute att = h5obj.createAttribute(name, *datatype, dataspace);
    att.write(*datatype, &value);
}

template <>
inline void save_scalar_attribute (const H5::H5Location &h5obj, const std::string &name, const std::string &value)
{
    save_scalar_attribute(h5obj, name, value.c_str());
}

// see http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html

template <typename Derived>
void save (H5::CommonFG &h5group, const std::string &name, const Eigen::EigenBase<Derived> &mat, const H5::DSetCreatPropList &plist=H5::DSetCreatPropList::DEFAULT)
{
    typedef typename Derived::Scalar Scalar;
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    H5::DataSet dataset = h5group.createDataSet(name, *datatype, dataspace, plist);

    bool written = false;  // flag will be true when the data has been written
    if (mat.derived().Flags & Eigen::RowMajor)
    {
        // the matrix is stored in a row major order; see if it is contiguous
        if (mat.derived().outerStride() == mat.cols())
        {
            // the stride between rows is the number of columns means there is no padding between
            // rows, so the data is contiguous and we can write the data directly from memory
            // without copying.
            dataset.write(mat.derived().data(), *datatype);
            written = true;
        }
        else if (mat.derived().innerStride() == 1)
        {
            // inner stride == 1 is a sanity check. Only matrices made with unconventional maps
            // would have inner stride != 1, and they will be handled below by first copying the
            // input matrix.

            // write the matrix by rows to the dataset using the dataspace made above
            written = internal::write_mat_by_rows(mat, datatype, &dataset, &dataspace);
        }
    }
    else
    {
        written = internal::write_col_mat(mat, datatype, &dataset, &dataspace);
    }

    if (!written)
    {
        // data has not yet been written, so there is nothing else to try but copy the input
        // matrix to a row major matrix and write it.
        const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
        dataset.write(row_major_mat.data(), *datatype);
    }
}

template <typename Derived>
void save_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::EigenBase<Derived> &mat)
{
    typedef typename Derived::Scalar Scalar;
    const Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> row_major_mat(mat);
    const H5::DataSpace dataspace = internal::create_dataspace(mat);
    const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
    H5::Attribute dataset = h5obj.createAttribute(name, *datatype, dataspace);
    dataset.write(*datatype, row_major_mat.data());
}

namespace internal
{
    // H5::Attribute and H5::DataSet both have similar API's, and although they
    // share a common base class, the relevant methods are not virtual.  Worst
    // of all, they take their arguments in different orders!

    template <typename Scalar>
    inline void read_data (const H5::DataSet &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(data, datatype);
    }

    template <typename Scalar>
    inline void read_data (const H5::Attribute &dataset, Scalar *data, const H5::DataType &datatype)
    {
        dataset.read(datatype, data);
    }

    template <typename Derived, typename DataSet>
    void _load (const DataSet &dataset, const Eigen::DenseBase<Derived> &mat)
    {
        typedef typename Derived::Scalar Scalar;
        const H5::DataSpace dataspace = dataset.getSpace();
        const std::size_t ndims = dataspace.getSimpleExtentNdims();
        assert(ndims > 0);
        const std::size_t dimensions_size = 2;
        hsize_t dimensions[dimensions_size];
        dimensions[1] = 1; // in case it's 1D
        if (ndims > dimensions_size) {
            throw std::runtime_error("HDF5 array has too many dimensions.");
        }
        dataspace.getSimpleExtentDims(dimensions);
        const hsize_t rows = dimensions[0], cols = dimensions[1];
        const H5::DataType * const datatype = DatatypeSpecialization<Scalar>::get();
        Eigen::DenseBase<Derived> &mat_ = const_cast<Eigen::DenseBase<Derived> &>(mat);
        bool written = false;
        if (mat.Flags & Eigen::RowMajor || dimensions[0] == 1 || dimensions[1] == 1)
        {
            // mat is already row major; resize it and read into it
            mat_.derived().resize(rows, cols);
            Derived::Index stride = mat_.derived().outerStride();
            if (stride == cols || (stride == rows && cols == 1))
            {
                // mat has natural stride, so read directly into its data block
                internal::read_data(dataset, mat_.derived().data(), *datatype);
                written = true;
            }
        }

        if (!written)
        {
            // input is col major or has unnatural stride; read into a temp and copy it
            Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> temp(rows, cols);
            internal::read_data(dataset, temp.data(), *datatype);
            mat_ = temp;
            written = true;
        }
    }
}

template <typename Derived>
void load (const H5::CommonFG &h5group, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::DataSet dataset = h5group.openDataSet(name);
    internal::_load(dataset, mat);
}

template <typename Derived>
void load_attribute (const H5::H5Location &h5obj, const std::string &name, const Eigen::DenseBase<Derived> &mat)
{
    const H5::Attribute dataset = h5obj.openAttribute(name);
    internal::_load(dataset, mat);
}

} // namespace EigenHDF5

#endif
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mwidgetfadeanimation.h"
#include "mwidgetfadeanimation_p.h"
#include "manimationcreator.h"

#include <QPauseAnimation>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <mwidgetcontroller.h>

void MWidgetFadeAnimationPrivate::init()
{
    Q_Q(MWidgetFadeAnimation);

    direction = MWidgetFadeAnimation::In;
    QSequentialAnimationGroup *delayedAnimation = new QSequentialAnimationGroup;
    delay = new QPauseAnimation;
    opacityAnimation = new QPropertyAnimation;
    opacityAnimation->setPropertyName("opacity");
    delayedAnimation->addAnimation(delay);
    delayedAnimation->addAnimation(opacityAnimation);
    q->addAnimation(delayedAnimation);
}

MWidgetFadeAnimation::MWidgetFadeAnimation(MWidgetFadeAnimationPrivate *dd, QObject *parent) :
    MAbstractWidgetAnimation(dd, parent)
{
    Q_D(MWidgetFadeAnimation);

    d->init();
}

MWidgetFadeAnimation::MWidgetFadeAnimation(QObject *parent) :
    MAbstractWidgetAnimation(new MWidgetFadeAnimationPrivate, parent)
{
    Q_D(MWidgetFadeAnimation);

    d->init();
}

MWidgetFadeAnimation::~MWidgetFadeAnimation()
{
}

void MWidgetFadeAnimation::setTargetWidget(MWidgetController *widget)
{
    Q_D(MWidgetFadeAnimation);
    MAbstractWidgetAnimation::setTargetWidget(widget);

    d->played = false;
    d->opacityAnimation->setTargetObject(targetWidget());
}

void MWidgetFadeAnimation::restoreTargetWidgetState()
{
    Q_D(MWidgetFadeAnimation);
    if (d->played)
        targetWidget()->setOpacity(d->originalOpacity);
}

void MWidgetFadeAnimation::setTransitionDirection(TransitionDirection direction)
{
    Q_D(MWidgetFadeAnimation);

    d->direction = direction;

    if (d->direction == In)
        style().setObjectName("In");
    else
        style().setObjectName("Out");
}

void MWidgetFadeAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
    Q_D(MWidgetFadeAnimation);

    if (!d->targetWidget)
        return;

    if (oldState == QAbstractAnimation::Stopped &&
        newState == QAbstractAnimation::Running)
    {
        if (style().objectName().isNull())
            style().setObjectName("In");

        d->originalOpacity = d->targetWidget->opacity();

        if (d->direction == In) {
            targetWidget()->setOpacity(0);
            d->opacityAnimation->setStartValue(0);
            d->opacityAnimation->setEndValue(d->originalOpacity);
        } else {
            d->opacityAnimation->setStartValue(d->originalOpacity);
            d->opacityAnimation->setEndValue(0);
        }

        d->played = true;

        d->delay->setDuration(style()->delay());
        d->opacityAnimation->setDuration(style()->duration());
    }
}

M_REGISTER_ANIMATION(MWidgetFadeAnimation)
<commit_msg>Fixes: NB#260204 - View/Action Menu transition parameters are slightly off<commit_after>/***************************************************************************
**
** Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mwidgetfadeanimation.h"
#include "mwidgetfadeanimation_p.h"
#include "manimationcreator.h"

#include <QPauseAnimation>
#include <QPropertyAnimation>
#include <QSequentialAnimationGroup>
#include <mwidgetcontroller.h>

void MWidgetFadeAnimationPrivate::init()
{
    Q_Q(MWidgetFadeAnimation);

    direction = MWidgetFadeAnimation::In;
    QSequentialAnimationGroup *delayedAnimation = new QSequentialAnimationGroup;
    delay = new QPauseAnimation;
    opacityAnimation = new QPropertyAnimation;
    opacityAnimation->setPropertyName("opacity");
    delayedAnimation->addAnimation(delay);
    delayedAnimation->addAnimation(opacityAnimation);
    q->addAnimation(delayedAnimation);
}

MWidgetFadeAnimation::MWidgetFadeAnimation(MWidgetFadeAnimationPrivate *dd, QObject *parent) :
    MAbstractWidgetAnimation(dd, parent)
{
    Q_D(MWidgetFadeAnimation);

    d->init();
}

MWidgetFadeAnimation::MWidgetFadeAnimation(QObject *parent) :
    MAbstractWidgetAnimation(new MWidgetFadeAnimationPrivate, parent)
{
    Q_D(MWidgetFadeAnimation);

    d->init();
}

MWidgetFadeAnimation::~MWidgetFadeAnimation()
{
}

void MWidgetFadeAnimation::setTargetWidget(MWidgetController *widget)
{
    Q_D(MWidgetFadeAnimation);
    MAbstractWidgetAnimation::setTargetWidget(widget);

    d->played = false;
    d->opacityAnimation->setTargetObject(targetWidget());
}

void MWidgetFadeAnimation::restoreTargetWidgetState()
{
    Q_D(MWidgetFadeAnimation);
    if (d->played)
        targetWidget()->setOpacity(d->originalOpacity);
}

void MWidgetFadeAnimation::setTransitionDirection(TransitionDirection direction)
{
    Q_D(MWidgetFadeAnimation);

    d->direction = direction;

    if (d->direction == In)
        style().setObjectName("In");
    else
        style().setObjectName("Out");
}

void MWidgetFadeAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
{
    Q_D(MWidgetFadeAnimation);

    if (!d->targetWidget)
        return;

    if (oldState == QAbstractAnimation::Stopped &&
        newState == QAbstractAnimation::Running)
    {
        if (style().objectName().isNull())
            style().setObjectName("In");

        d->originalOpacity = d->targetWidget->opacity();

        if (d->direction == In) {
            targetWidget()->setOpacity(0);
            d->opacityAnimation->setStartValue(0);
            d->opacityAnimation->setEndValue(d->originalOpacity);
        } else {
            d->opacityAnimation->setStartValue(d->originalOpacity);
            d->opacityAnimation->setEndValue(0);
        }

        d->played = true;

        d->delay->setDuration(style()->delay());
        d->opacityAnimation->setEasingCurve(style()->easingCurve());
        d->opacityAnimation->setDuration(style()->duration());
    }
}

M_REGISTER_ANIMATION(MWidgetFadeAnimation)
<|endoftext|>


<commit_before>/*
Copyright (C) 2011 by Mike McQuaid

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

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

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

#include "qsearchfield.h"

#include <QLineEdit>
#include <QVBoxLayout>
#include <QToolButton>
#include <QStyle>

#include <QDir>
#include <QDebug>

class QSearchFieldPrivate : public QObject
{
public:
    QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
        : QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
    QPointer<QLineEdit> lineEdit;
    QPointer<QToolButton> clearButton;
};

QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
    QLineEdit *lineEdit = new QLineEdit(this);
    connect(lineEdit, SIGNAL(textChanged(QString)),
            this, SIGNAL(textChanged(QString)));
    connect(lineEdit, SIGNAL(editingFinished()),
            this, SIGNAL(editingFinished()));
    connect(lineEdit, SIGNAL(textChanged(QString)),
            this, SLOT(setText(QString)));

    QToolButton *clearButton = new QToolButton(this);
    QPixmap clearIcon(QString(":/Qocoa/qsearchfield_nonmac.png"));
    clearButton->setIcon(QIcon(clearIcon));
    clearButton->setIconSize(clearIcon.size());
    clearButton->setFixedSize(clearIcon.size());
    clearButton->setStyleSheet("border: none;");
    clearButton->hide();
    connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));

    const int frameWidth = lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    lineEdit->setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(clearIcon.width() - frameWidth - 1));
    const int width = qMax(lineEdit->minimumSizeHint().width(), clearButton->width() + frameWidth * 2);
    const int height = qMax(lineEdit->minimumSizeHint().height(), clearButton->height() + frameWidth * 2);
    lineEdit->setMinimumSize(width, height);

    pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);
    layout->addWidget(lineEdit);
}

void QSearchField::setText(const QString &text)
{
    Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
    if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
        return;

    pimpl->clearButton->setVisible(!text.isEmpty());

    if (text != this->text())
        pimpl->lineEdit->setText(text);
}

void QSearchField::setPlaceholderText(const QString &text)
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return;

    pimpl->lineEdit->setPlaceholderText(text);
}

void QSearchField::clear()
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return;

    pimpl->lineEdit->clear();
}

QString QSearchField::text() const
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return QString();

    return pimpl->lineEdit->text();
}

void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
    Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
    if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
        return;

    QWidget::resizeEvent(resizeEvent);
    const int frameWidth = pimpl->lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    const int x = sizeHint().width() - pimpl->clearButton->width() - frameWidth;
    const int y = sizeHint().height() - pimpl->clearButton->height()/2 - frameWidth*2;
    pimpl->clearButton->move(x, y);
}
<commit_msg>Fix non-Mac QSearchField button placement.<commit_after>/*
Copyright (C) 2011 by Mike McQuaid

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

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

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

#include "qsearchfield.h"

#include <QLineEdit>
#include <QVBoxLayout>
#include <QToolButton>
#include <QStyle>

#include <QDir>
#include <QDebug>

class QSearchFieldPrivate : public QObject
{
public:
    QSearchFieldPrivate(QSearchField *searchField, QLineEdit *lineEdit, QToolButton *clearButton)
        : QObject(searchField), lineEdit(lineEdit), clearButton(clearButton) {}
    int lineEditFrameWidth() const {
        return lineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    }
    int clearButtonPaddedWidth() const {
        return clearButton->width() + lineEditFrameWidth() * 2;
    }
    int clearButtonPaddedHeight() const {
        return clearButton->height() + lineEditFrameWidth() * 2;
    }
    QPointer<QLineEdit> lineEdit;
    QPointer<QToolButton> clearButton;
};

QSearchField::QSearchField(QWidget *parent) : QWidget(parent)
{
    QLineEdit *lineEdit = new QLineEdit(this);
    connect(lineEdit, SIGNAL(textChanged(QString)),
            this, SIGNAL(textChanged(QString)));
    connect(lineEdit, SIGNAL(editingFinished()),
            this, SIGNAL(editingFinished()));
    connect(lineEdit, SIGNAL(textChanged(QString)),
            this, SLOT(setText(QString)));

    QToolButton *clearButton = new QToolButton(this);
    QPixmap clearIcon(QString(":/Qocoa/qsearchfield_nonmac.png"));
    clearButton->setIcon(QIcon(clearIcon));
    clearButton->setIconSize(clearIcon.size());
    clearButton->setFixedSize(clearIcon.size());
    clearButton->setStyleSheet("border: none;");
    clearButton->hide();
    connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));

    pimpl = new QSearchFieldPrivate(this, lineEdit, clearButton);

    lineEdit->setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(pimpl->clearButtonPaddedWidth()));
    const int width = qMax(lineEdit->minimumSizeHint().width(), pimpl->clearButtonPaddedWidth());
    const int height = qMax(lineEdit->minimumSizeHint().height(), pimpl->clearButtonPaddedHeight());
    lineEdit->setMinimumSize(width, height);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);
    layout->addWidget(lineEdit);
}

void QSearchField::setText(const QString &text)
{
    Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
    if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
        return;

    pimpl->clearButton->setVisible(!text.isEmpty());

    if (text != this->text())
        pimpl->lineEdit->setText(text);
}

void QSearchField::setPlaceholderText(const QString &text)
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return;

    pimpl->lineEdit->setPlaceholderText(text);
}

void QSearchField::clear()
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return;

    pimpl->lineEdit->clear();
}

QString QSearchField::text() const
{
    Q_ASSERT(pimpl && pimpl->lineEdit);
    if (!(pimpl && pimpl->lineEdit))
        return QString();

    return pimpl->lineEdit->text();
}

void QSearchField::resizeEvent(QResizeEvent *resizeEvent)
{
    Q_ASSERT(pimpl && pimpl->clearButton && pimpl->lineEdit);
    if (!(pimpl && pimpl->clearButton && pimpl->lineEdit))
        return;

    QWidget::resizeEvent(resizeEvent);
    const int x = width() - pimpl->clearButtonPaddedWidth();
    const int y = (height() - pimpl->clearButton->height())/2;
    pimpl->clearButton->move(x, y);
}
<|endoftext|>