<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "SubProblem.h"
#include "Factory.h"
#include "MooseMesh.h"
#include "Conversion.h"
#include "Function.h"

template<>
InputParameters validParams<SubProblem>()
{
  InputParameters params = validParams<Problem>();
  params.addRequiredParam<MooseMesh *>("mesh", "The Mesh");
  params.addParam<Problem *>("parent", NULL, "This problem's parent problem (if any)");
  return params;
}

// SubProblem /////

SubProblem::SubProblem(const std::string & name, InputParameters parameters) :
    Problem(name, parameters),
    _parent(parameters.get<Problem *>("parent") == NULL ? this : parameters.get<Problem *>("parent")),
    _mesh(*parameters.get<MooseMesh *>("mesh")),
    _eq(_parent == this ? *new EquationSystems(_mesh) : _parent->es()),
    _transient(false),
    _time(_eq.parameters.set<Real>("time")),
    _time_old(_eq.parameters.set<Real>("time_old")),
    _t_step(_eq.parameters.set<int>("t_step")),
    _dt(_eq.parameters.set<Real>("dt"))
{
  if (_parent == this)
  {
    _time = 0.0;
    _time_old = 0.0;
    _t_step = 0;
    _dt = 0;
    _dt_old = _dt;
    _eq.parameters.set<Problem *>("_problem") = this;
  }
}

SubProblem::~SubProblem()
{
  if (_parent == this)
    delete &_eq;
}

Moose::CoordinateSystemType
SubProblem::getCoordSystem(SubdomainID sid)
{
  std::map<SubdomainID, Moose::CoordinateSystemType>::iterator it = _coord_sys.find(sid);
  if (it != _coord_sys.end())
    return (*it).second;
  else
    mooseError("Requested subdomain does not exist.");
}

void
SubProblem::setCoordSystem(const std::vector<SubdomainName> & blocks, const std::vector<std::string> & coord_sys)
{
  const std::set<SubdomainID> & subdomains = _mesh.meshSubdomains();
  if (blocks.size() == 0)
  {
    // no blocks specified -> assume the whole domain
    Moose::CoordinateSystemType coord_type = Moose::COORD_XYZ;                          // all is going to be XYZ by default
    if (coord_sys.size() == 0)
      ; // relax, do nothing
    else if (coord_sys.size() == 1)
      coord_type = Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[0]);      // one system specified, the whole domain is going to have that system
    else
      mooseError("Multiple coordinate systems specified, but no blocks given.");

    for (std::set<SubdomainID>::const_iterator it = subdomains.begin(); it != subdomains.end(); ++it)
      _coord_sys[*it] = coord_type;
  }
  else
  {
    if (blocks.size() != coord_sys.size())
      mooseError("Number of blocks and coordinate systems does not match.");

    for (unsigned int i = 0; i < blocks.size(); i++)
    {
      SubdomainID sid = _mesh.getSubdomainID(blocks[i]);
      Moose::CoordinateSystemType coord_type = Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[i]);
      _coord_sys[sid] = coord_type;
    }

    for (std::set<SubdomainID>::const_iterator it = subdomains.begin(); it != subdomains.end(); ++it)
    {
      SubdomainID sid = *it;
      if (_coord_sys.find(sid) == _coord_sys.end())
        mooseError("Subdomain '" + Moose::stringify(sid) + "' does not have a coordinate system specified.");
    }
  }
}

void
SubProblem::init()
{
  _eq.init();
}

std::vector<SubdomainID>
SubProblem::getMaterialPropertyBlocks(const std::string prop_name)
{
  std::set<SubdomainID> blocks;
  std::vector<SubdomainID> blocks_vec;

  for(std::map<unsigned int, std::set<std::string> >::iterator it = _map_material_props.begin();
      it != _map_material_props.end();
      ++it)
  {
    std::set<std::string> & prop_names = it->second;
    SubdomainID block = it->first;

    for(std::set<std::string>::iterator name_it = prop_names.begin();
        name_it != prop_names.end();
        ++name_it)
    {
      if(*name_it == prop_name)
        blocks.insert(block);
    }
  }

  // Copy it out to a vector for convenience
  blocks_vec.reserve(blocks.size());

  for(std::set<SubdomainID>::iterator it = blocks.begin();
      it != blocks.end();
      ++it)
    blocks_vec.push_back(*it);

  return blocks_vec;
}

std::vector<SubdomainName>
SubProblem::getMaterialPropertyBlockNames(const std::string prop_name)
{
  std::vector<SubdomainID> blocks = getMaterialPropertyBlocks(prop_name);
  std::vector<SubdomainName> block_names(blocks.size());

  for (unsigned int i=0; i<blocks.size(); ++i)
  {
    std::stringstream ss;
    ss << blocks[i];
    block_names[i] = ss.str();
  }
  return block_names;
}

void
SubProblem::storeMatPropName(SubdomainID block_id, const std::string & name)
{
  _map_material_props[block_id].insert(name);
}

void
SubProblem::checkMatProp(SubdomainID block_id, const std::string & name)
{
  std::map<unsigned int, std::set<std::string> >::iterator it;
  if ((it = _map_material_props.find(block_id)) != _map_material_props.end())
  {
    std::set<std::string>::iterator jt;
    if ((jt = (*it).second.find(name)) == (*it).second.end())
      mooseError("Material property '" + name + "' is not defined on block " + Moose::stringify(block_id));
  }
  else
  {
    mooseError("No material defined on block " + Moose::stringify(block_id));
  }
}
<commit_msg>Improve error message<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

#include "SubProblem.h"
#include "Factory.h"
#include "MooseMesh.h"
#include "Conversion.h"
#include "Function.h"

template<>
InputParameters validParams<SubProblem>()
{
  InputParameters params = validParams<Problem>();
  params.addRequiredParam<MooseMesh *>("mesh", "The Mesh");
  params.addParam<Problem *>("parent", NULL, "This problem's parent problem (if any)");
  return params;
}

// SubProblem /////

SubProblem::SubProblem(const std::string & name, InputParameters parameters) :
    Problem(name, parameters),
    _parent(parameters.get<Problem *>("parent") == NULL ? this : parameters.get<Problem *>("parent")),
    _mesh(*parameters.get<MooseMesh *>("mesh")),
    _eq(_parent == this ? *new EquationSystems(_mesh) : _parent->es()),
    _transient(false),
    _time(_eq.parameters.set<Real>("time")),
    _time_old(_eq.parameters.set<Real>("time_old")),
    _t_step(_eq.parameters.set<int>("t_step")),
    _dt(_eq.parameters.set<Real>("dt"))
{
  if (_parent == this)
  {
    _time = 0.0;
    _time_old = 0.0;
    _t_step = 0;
    _dt = 0;
    _dt_old = _dt;
    _eq.parameters.set<Problem *>("_problem") = this;
  }
}

SubProblem::~SubProblem()
{
  if (_parent == this)
    delete &_eq;
}

Moose::CoordinateSystemType
SubProblem::getCoordSystem(SubdomainID sid)
{
  std::map<SubdomainID, Moose::CoordinateSystemType>::iterator it = _coord_sys.find(sid);
  if (it != _coord_sys.end())
    return (*it).second;
  else
  {
    std::stringstream err;
    err << "Requested subdomain "
        << sid
        << " does not exist.";
    mooseError(err.str());
  }
}

void
SubProblem::setCoordSystem(const std::vector<SubdomainName> & blocks, const std::vector<std::string> & coord_sys)
{
  const std::set<SubdomainID> & subdomains = _mesh.meshSubdomains();
  if (blocks.size() == 0)
  {
    // no blocks specified -> assume the whole domain
    Moose::CoordinateSystemType coord_type = Moose::COORD_XYZ;                          // all is going to be XYZ by default
    if (coord_sys.size() == 0)
      ; // relax, do nothing
    else if (coord_sys.size() == 1)
      coord_type = Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[0]);      // one system specified, the whole domain is going to have that system
    else
      mooseError("Multiple coordinate systems specified, but no blocks given.");

    for (std::set<SubdomainID>::const_iterator it = subdomains.begin(); it != subdomains.end(); ++it)
      _coord_sys[*it] = coord_type;
  }
  else
  {
    if (blocks.size() != coord_sys.size())
      mooseError("Number of blocks and coordinate systems does not match.");

    for (unsigned int i = 0; i < blocks.size(); i++)
    {
      SubdomainID sid = _mesh.getSubdomainID(blocks[i]);
      Moose::CoordinateSystemType coord_type = Moose::stringToEnum<Moose::CoordinateSystemType>(coord_sys[i]);
      _coord_sys[sid] = coord_type;
    }

    for (std::set<SubdomainID>::const_iterator it = subdomains.begin(); it != subdomains.end(); ++it)
    {
      SubdomainID sid = *it;
      if (_coord_sys.find(sid) == _coord_sys.end())
        mooseError("Subdomain '" + Moose::stringify(sid) + "' does not have a coordinate system specified.");
    }
  }
}

void
SubProblem::init()
{
  _eq.init();
}

std::vector<SubdomainID>
SubProblem::getMaterialPropertyBlocks(const std::string prop_name)
{
  std::set<SubdomainID> blocks;
  std::vector<SubdomainID> blocks_vec;

  for(std::map<unsigned int, std::set<std::string> >::iterator it = _map_material_props.begin();
      it != _map_material_props.end();
      ++it)
  {
    std::set<std::string> & prop_names = it->second;
    SubdomainID block = it->first;

    for(std::set<std::string>::iterator name_it = prop_names.begin();
        name_it != prop_names.end();
        ++name_it)
    {
      if(*name_it == prop_name)
        blocks.insert(block);
    }
  }

  // Copy it out to a vector for convenience
  blocks_vec.reserve(blocks.size());

  for(std::set<SubdomainID>::iterator it = blocks.begin();
      it != blocks.end();
      ++it)
    blocks_vec.push_back(*it);

  return blocks_vec;
}

std::vector<SubdomainName>
SubProblem::getMaterialPropertyBlockNames(const std::string prop_name)
{
  std::vector<SubdomainID> blocks = getMaterialPropertyBlocks(prop_name);
  std::vector<SubdomainName> block_names(blocks.size());

  for (unsigned int i=0; i<blocks.size(); ++i)
  {
    std::stringstream ss;
    ss << blocks[i];
    block_names[i] = ss.str();
  }
  return block_names;
}

void
SubProblem::storeMatPropName(SubdomainID block_id, const std::string & name)
{
  _map_material_props[block_id].insert(name);
}

void
SubProblem::checkMatProp(SubdomainID block_id, const std::string & name)
{
  std::map<unsigned int, std::set<std::string> >::iterator it;
  if ((it = _map_material_props.find(block_id)) != _map_material_props.end())
  {
    std::set<std::string>::iterator jt;
    if ((jt = (*it).second.find(name)) == (*it).second.end())
      mooseError("Material property '" + name + "' is not defined on block " + Moose::stringify(block_id));
  }
  else
  {
    mooseError("No material defined on block " + Moose::stringify(block_id));
  }
}
<|endoftext|>


<commit_before>/*
* UsbDk filter/redirector driver
*
* Copyright (c) 2013  Red Hat, Inc.
*
* Authors:
*  Dmitry Fleytman  <dfleytma@redhat.com>
*
*/

#include "driver.h"
#include "Filter.h"
#include "device.tmh"

// {C0F2DADE-8235-4065-89A8-58DB74DDC9AC}
DEFINE_GUID(GUID_USBDK_CLONE_PDO,
    0xc0f2dade, 0x8235, 0x4065, 0x89, 0xa8, 0x58, 0xdb, 0x74, 0xdd, 0xc9, 0xac);

typedef struct _CONTROL_DEVICE_EXTENSION {
} PDO_CLONE_EXTENSION, *PPDO_CLONE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_CLONE_EXTENSION, PdoCloneGetData)

static WDFDEVICE
UsbDkClonePdo(WDFDEVICE ParentDevice)
{
    WDFDEVICE              ClonePdo;
    NTSTATUS               status;
    PWDFDEVICE_INIT        DevInit;
    WDF_OBJECT_ATTRIBUTES  DevAttr;

    PAGED_CODE();

    DevInit = WdfPdoInitAllocate(ParentDevice);

    if (DevInit == NULL) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAllocate returned NULL");
        return NULL;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DevAttr, PDO_CLONE_EXTENSION);

#define CLONE_HARDWARE_IDS      L"USB\\Vid_FEED&Pid_CAFE&Rev_0001\0USB\\Vid_FEED&Pid_CAFE\0"
#define CLONE_COMPATIBLE_IDS    L"USB\\Class_FF&SubClass_FF&Prot_FF\0USB\\Class_FF&SubClass_FF\0USB\\Class_FF\0"
#define CLONE_INSTANCE_ID       L"111222333"

    DECLARE_CONST_UNICODE_STRING(CloneHwId, CLONE_HARDWARE_IDS);
    DECLARE_CONST_UNICODE_STRING(CloneCompatId, CLONE_COMPATIBLE_IDS);
    DECLARE_CONST_UNICODE_STRING(CloneInstanceId, CLONE_INSTANCE_ID);

    //TODO: Check error codes
    WdfPdoInitAssignDeviceID(DevInit, &CloneHwId);
    WdfPdoInitAddCompatibleID(DevInit, &CloneCompatId);
    WdfPdoInitAddHardwareID(DevInit, &CloneCompatId);
    WdfPdoInitAssignInstanceID(DevInit, &CloneInstanceId);

    status = WdfDeviceCreate(&DevInit, &DevAttr, &ClonePdo);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate returned %!STATUS!", status);
        WdfDeviceInitFree(DevInit);
        return NULL;
    }

    return ClonePdo;
}

VOID UsbDkQDRPostProcessWi(_In_ PVOID Context)
{
    PDEVICE_CONTEXT Ctx = (PDEVICE_CONTEXT) Context;

    ASSERT(Ctx->QDRIrp != NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Entry");

    PDEVICE_RELATIONS Relations = (PDEVICE_RELATIONS) Ctx->QDRIrp->IoStatus.Information;

    if (Relations)
    {
        if (Relations->Count > 0)
        {
            Ctx->ClonedPdo = Relations->Objects[0];

            //TODO: Temporary to allow normal USB hub driver unload
            ObDereferenceObject(Ctx->ClonedPdo);

            Relations->Objects[0] = WdfDeviceWdmGetDeviceObject(Ctx->PdoClone);
            ObReferenceObject(Relations->Objects[0]);

            TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Replaced PDO 0x%p with 0x%p",
                Ctx->ClonedPdo, Relations->Objects[0]);
        }
    }

    PIRP QDRIrp = Ctx->QDRIrp;
    Ctx->QDRIrp = NULL;

    IoCompleteRequest(QDRIrp, IO_NO_INCREMENT);
}

NTSTATUS UsbDkQDRPostProcess(_In_  PDEVICE_OBJECT DeviceObject, _In_  PIRP Irp, _In_  PVOID Context)
{
    PDEVICE_CONTEXT Ctx = (PDEVICE_CONTEXT)Context;

    UNREFERENCED_PARAMETER(DeviceObject);

    if (Irp->PendingReturned)
    {
        IoMarkIrpPending(Irp);
    }

    ASSERT(Ctx->QDRIrp == NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Queuing work item");

    Ctx->QDRIrp = Irp;
    Ctx->QDRCompletionWorkItem.Enqueue();

    return STATUS_MORE_PROCESSING_REQUIRED;
}

static NTSTATUS UsbDkQDRPreProcess(_In_ WDFDEVICE Device, _Inout_  PIRP Irp)
{
     PDEVICE_CONTEXT ctx = DeviceGetContext(Device);
     PDEVICE_OBJECT wdmDevice = WdfDeviceWdmGetDeviceObject(Device);

    PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);

    if (BusRelations != irpStack->Parameters.QueryDeviceRelations.Type)
    {
        IoSkipCurrentIrpStackLocation(Irp);
    }
    else
    {
        IoCopyCurrentIrpStackLocationToNext(Irp);
        IoSetCompletionRoutineEx(wdmDevice, Irp, UsbDkQDRPostProcess, ctx, TRUE, FALSE, FALSE);
    }

    return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

static NTSTATUS
UsbDkSetupFiltering(_In_ PWDFDEVICE_INIT DeviceInit)
{
    UCHAR minorCode = IRP_MN_QUERY_DEVICE_RELATIONS;

    PAGED_CODE();

    WdfFdoInitSetFilter(DeviceInit);

    NTSTATUS status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
                                                                  UsbDkQDRPreProcess,
                                                                  IRP_MJ_PNP, &minorCode, 1);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! status: %!STATUS!", status);
    }

    return status;
}

NTSTATUS
UsbDkCreateDevice(_Inout_ PWDFDEVICE_INIT DeviceInit)
{
    WDF_OBJECT_ATTRIBUTES   deviceAttributes;
    PDEVICE_CONTEXT deviceContext;
    WDFDEVICE device;
    NTSTATUS status;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Entry");

    status = UsbDkSetupFiltering(DeviceInit);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);

    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate status: %!STATUS!", status);
        return status;
    }

    if (UsbDkShouldAttach(device))
    {
        deviceContext = DeviceGetContext(device);
        deviceContext->IOTarget = WdfDeviceGetIoTarget(device);
        deviceContext->PdoClone = UsbDkClonePdo(device);
        deviceContext->QDRIrp = NULL;

        new (&deviceContext->QDRCompletionWorkItem) CWdfWorkitem(device, UsbDkQDRPostProcessWi, deviceContext);
        status = deviceContext->QDRCompletionWorkItem.Create();

        ULONG traceLevel = NT_SUCCESS(status) ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_ERROR;
        TraceEvents(traceLevel, TRACE_DEVICE, "%!FUNC! Attachment status: %!STATUS!", status);
    }
    else
    {
        status = STATUS_NOT_SUPPORTED;
        TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Not attached");
    }

    return status;
}
<commit_msg>UsbDk: ClonePdo beautifications<commit_after>/*
* UsbDk filter/redirector driver
*
* Copyright (c) 2013  Red Hat, Inc.
*
* Authors:
*  Dmitry Fleytman  <dfleytma@redhat.com>
*
*/

#include "driver.h"
#include "Filter.h"
#include "device.tmh"

// {C0F2DADE-8235-4065-89A8-58DB74DDC9AC}
DEFINE_GUID(GUID_USBDK_CLONE_PDO,
    0xc0f2dade, 0x8235, 0x4065, 0x89, 0xa8, 0x58, 0xdb, 0x74, 0xdd, 0xc9, 0xac);

typedef struct _CONTROL_DEVICE_EXTENSION {
} PDO_CLONE_EXTENSION, *PPDO_CLONE_EXTENSION;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PDO_CLONE_EXTENSION, PdoCloneGetData)

static WDFDEVICE
UsbDkClonePdo(WDFDEVICE ParentDevice)
{
    WDFDEVICE              ClonePdo;
    NTSTATUS               status;
    PWDFDEVICE_INIT        DevInit;
    WDF_OBJECT_ATTRIBUTES  DevAttr;

    PAGED_CODE();

    DevInit = WdfPdoInitAllocate(ParentDevice);

    if (DevInit == NULL) {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfPdoInitAllocate returned NULL");
        return WDF_NO_HANDLE;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DevAttr, PDO_CLONE_EXTENSION);

#define CLONE_HARDWARE_IDS      L"USB\\Vid_FEED&Pid_CAFE&Rev_0001\0USB\\Vid_FEED&Pid_CAFE\0"
#define CLONE_COMPATIBLE_IDS    L"USB\\Class_FF&SubClass_FF&Prot_FF\0USB\\Class_FF&SubClass_FF\0USB\\Class_FF\0"
#define CLONE_INSTANCE_ID       L"111222333"

    DECLARE_CONST_UNICODE_STRING(CloneHwId, CLONE_HARDWARE_IDS);
    DECLARE_CONST_UNICODE_STRING(CloneCompatId, CLONE_COMPATIBLE_IDS);
    DECLARE_CONST_UNICODE_STRING(CloneInstanceId, CLONE_INSTANCE_ID);

    //TODO: Check error codes
    WdfPdoInitAssignDeviceID(DevInit, &CloneHwId);
    WdfPdoInitAddCompatibleID(DevInit, &CloneCompatId);
    WdfPdoInitAddHardwareID(DevInit, &CloneCompatId);
    WdfPdoInitAssignInstanceID(DevInit, &CloneInstanceId);

    status = WdfDeviceCreate(&DevInit, &DevAttr, &ClonePdo);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate returned %!STATUS!", status);
        WdfDeviceInitFree(DevInit);
        return WDF_NO_HANDLE;
    }

    return ClonePdo;
}

VOID UsbDkQDRPostProcessWi(_In_ PVOID Context)
{
    PDEVICE_CONTEXT Ctx = (PDEVICE_CONTEXT) Context;

    ASSERT(Ctx->QDRIrp != NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Entry");

    PDEVICE_RELATIONS Relations = (PDEVICE_RELATIONS) Ctx->QDRIrp->IoStatus.Information;

    if (Relations)
    {
        if (Relations->Count > 0)
        {
            Ctx->ClonedPdo = Relations->Objects[0];

            //TODO: Temporary to allow normal USB hub driver unload
            ObDereferenceObject(Ctx->ClonedPdo);

            Relations->Objects[0] = WdfDeviceWdmGetDeviceObject(Ctx->PdoClone);
            ObReferenceObject(Relations->Objects[0]);

            TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Replaced PDO 0x%p with 0x%p",
                Ctx->ClonedPdo, Relations->Objects[0]);
        }
    }

    PIRP QDRIrp = Ctx->QDRIrp;
    Ctx->QDRIrp = NULL;

    IoCompleteRequest(QDRIrp, IO_NO_INCREMENT);
}

NTSTATUS UsbDkQDRPostProcess(_In_  PDEVICE_OBJECT DeviceObject, _In_  PIRP Irp, _In_  PVOID Context)
{
    PDEVICE_CONTEXT Ctx = (PDEVICE_CONTEXT)Context;

    UNREFERENCED_PARAMETER(DeviceObject);

    if (Irp->PendingReturned)
    {
        IoMarkIrpPending(Irp);
    }

    ASSERT(Ctx->QDRIrp == NULL);

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Queuing work item");

    Ctx->QDRIrp = Irp;
    Ctx->QDRCompletionWorkItem.Enqueue();

    return STATUS_MORE_PROCESSING_REQUIRED;
}

static NTSTATUS UsbDkQDRPreProcess(_In_ WDFDEVICE Device, _Inout_  PIRP Irp)
{
     PDEVICE_CONTEXT ctx = DeviceGetContext(Device);
     PDEVICE_OBJECT wdmDevice = WdfDeviceWdmGetDeviceObject(Device);

    PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);

    if (BusRelations != irpStack->Parameters.QueryDeviceRelations.Type)
    {
        IoSkipCurrentIrpStackLocation(Irp);
    }
    else
    {
        IoCopyCurrentIrpStackLocationToNext(Irp);
        IoSetCompletionRoutineEx(wdmDevice, Irp, UsbDkQDRPostProcess, ctx, TRUE, FALSE, FALSE);
    }

    return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

static NTSTATUS
UsbDkSetupFiltering(_In_ PWDFDEVICE_INIT DeviceInit)
{
    UCHAR minorCode = IRP_MN_QUERY_DEVICE_RELATIONS;

    PAGED_CODE();

    WdfFdoInitSetFilter(DeviceInit);

    NTSTATUS status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,
                                                                  UsbDkQDRPreProcess,
                                                                  IRP_MJ_PNP, &minorCode, 1);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! status: %!STATUS!", status);
    }

    return status;
}

NTSTATUS
UsbDkCreateDevice(_Inout_ PWDFDEVICE_INIT DeviceInit)
{
    WDF_OBJECT_ATTRIBUTES   deviceAttributes;
    PDEVICE_CONTEXT deviceContext;
    WDFDEVICE device;
    NTSTATUS status;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Entry");

    status = UsbDkSetupFiltering(DeviceInit);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);

    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "%!FUNC! WdfDeviceCreate status: %!STATUS!", status);
        return status;
    }

    if (UsbDkShouldAttach(device))
    {
        deviceContext = DeviceGetContext(device);
        deviceContext->IOTarget = WdfDeviceGetIoTarget(device);
        deviceContext->PdoClone = UsbDkClonePdo(device);
        deviceContext->QDRIrp = NULL;

        new (&deviceContext->QDRCompletionWorkItem) CWdfWorkitem(device, UsbDkQDRPostProcessWi, deviceContext);
        status = deviceContext->QDRCompletionWorkItem.Create();

        ULONG traceLevel = NT_SUCCESS(status) ? TRACE_LEVEL_INFORMATION : TRACE_LEVEL_ERROR;
        TraceEvents(traceLevel, TRACE_DEVICE, "%!FUNC! Attachment status: %!STATUS!", status);
    }
    else
    {
        status = STATUS_NOT_SUPPORTED;
        TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Not attached");
    }

    return status;
}
<|endoftext|>


<commit_before>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Convert.cpp                                                                 *
 *                                                                             *
 * Copyright (c) 2015 Tory Gaurnier                                            *
 *                                                                             *
 * Distributed under the MIT License.                                          *
 * See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "Convert.hpp"

#include <QApplication>
#include <QDebug>
#include <QScreen>

float Convert::pixels_per_meter = 0.0f;

/* * * * * * * * * * * * *
 * STATIC PUBLIC METHODS *
 * * * * * * * * * * * * */

void Convert::init(float Converts_per_screen_height) {
	pixels_per_meter = qApp->primaryScreen()->size().height() / Converts_per_screen_height;
}

float Convert::metersToPixels(float meters) {
	return meters * pixels_per_meter;
}

float Convert::pixelsToMeters(float pixels) {
	return pixels / pixels_per_meter;
}

b2Vec2 Convert::screenToWorldPos(b2Vec2 screen_pos) {
	b2Vec2 world_pos(
		screen_pos.x / pixels_per_meter,
		-(screen_pos.y / pixels_per_meter)
	);

	return world_pos;
}

float Convert::screenToWorldPosX(float screen_x) {
	return screenToWorldPos(b2Vec2(screen_x, 0.0f)).x;
}

float Convert::screenToWorldPosY(float screen_y) {
	return screenToWorldPos(b2Vec2(0.0f, screen_y)).y;
}

b2Vec2 Convert::worldToScreenPos(b2Vec2 world_pos) {
	b2Vec2 screen_pos(
		world_pos.x * pixels_per_meter,
		-(world_pos.y * pixels_per_meter)
	);

	return screen_pos;
}

float Convert::worldToScreenPosX(float world_x) {
	return worldToScreenPos(b2Vec2(world_x, 0.0f)).x;
}

float Convert::worldToScreenPosY(float world_y) {
	return worldToScreenPos(b2Vec2(0.0f, world_y)).y;
}
<commit_msg>Fixed typo<commit_after>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Convert.cpp                                                                 *
 *                                                                             *
 * Copyright (c) 2015 Tory Gaurnier                                            *
 *                                                                             *
 * Distributed under the MIT License.                                          *
 * See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "Convert.hpp"

#include <QApplication>
#include <QDebug>
#include <QScreen>

float Convert::pixels_per_meter = 0.0f;

/* * * * * * * * * * * * *
 * STATIC PUBLIC METHODS *
 * * * * * * * * * * * * */

void Convert::init(float meters_per_screen_height) {
	pixels_per_meter = qApp->primaryScreen()->size().height() / meters_per_screen_height;
}

float Convert::metersToPixels(float meters) {
	return meters * pixels_per_meter;
}

float Convert::pixelsToMeters(float pixels) {
	return pixels / pixels_per_meter;
}

b2Vec2 Convert::screenToWorldPos(b2Vec2 screen_pos) {
	b2Vec2 world_pos(
		screen_pos.x / pixels_per_meter,
		-(screen_pos.y / pixels_per_meter)
	);

	return world_pos;
}

float Convert::screenToWorldPosX(float screen_x) {
	return screenToWorldPos(b2Vec2(screen_x, 0.0f)).x;
}

float Convert::screenToWorldPosY(float screen_y) {
	return screenToWorldPos(b2Vec2(0.0f, screen_y)).y;
}

b2Vec2 Convert::worldToScreenPos(b2Vec2 world_pos) {
	b2Vec2 screen_pos(
		world_pos.x * pixels_per_meter,
		-(world_pos.y * pixels_per_meter)
	);

	return screen_pos;
}

float Convert::worldToScreenPosX(float world_x) {
	return worldToScreenPos(b2Vec2(world_x, 0.0f)).x;
}

float Convert::worldToScreenPosY(float world_y) {
	return worldToScreenPos(b2Vec2(0.0f, world_y)).y;
}
<|endoftext|>


<commit_before>//=============================================================================
// ■ shaders.cpp
//-----------------------------------------------------------------------------
//   VMDE中与着色器有关的全局变量和类都在这里。
//=============================================================================

#include "global.hpp"

Shaders::Shaders() {
}

void Shaders::add_string(GLenum type, const GLchar* source) {
	if (!source) error("source is null");
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	check_shader_compilation(shader, "shader compilation failed");
	shaders[shader_count] = shader;
	shader_count++;
	check_gl_error;
}

void Shaders::add_file(GLenum type, const char* filename) {
	log("adding shader file: %s", filename);
	char* source = Util::read_file(filename);
	add_string(type, source);
	free(source);
}

void Shaders::check_shader_compilation(GLuint shader, const char* msg) {
	GLint success;
	GLchar info_log[512];
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
	glGetShaderInfoLog(shader, 512, NULL, info_log);
	if (!success) error("%s:\n%s", msg, info_log);
	log("%s", info_log);
}

void Shaders::check_linkage(GLuint program, const char* msg) {
	GLint success;
	GLchar info_log[512];
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	glGetProgramInfoLog(program, 512, NULL, info_log);
	if (!success) error("%s:\n%s", msg, info_log);
	log("%s", info_log);
}

void Shaders::link_program() {
	// Link shaders
	program = glCreateProgram();
	for (size_t i = 0; i < shader_count; i++) {
		glAttachShader(program, shaders[i]);
	}
	glLinkProgram(program);
	check_linkage(program, "shaders linking failed");
	for (size_t i = 0; i < shader_count; i++) {
		glDeleteShader(shaders[i]);
	}
	check_gl_error;

	GLint loc = glGetUniformBlockIndex(program, "Matrices");
	glUniformBlockBinding(program, loc, 0);

	glGenBuffers(1, &UBO_matrix);
	glBindBuffer(GL_UNIFORM_BUFFER, UBO_matrix);
	glBufferData(GL_UNIFORM_BUFFER, 3 * sizeof(glm::mat4), 0, GL_STREAM_DRAW);
	glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

void Shaders::use() {
	glUseProgram(program);
	check_gl_error;
}

void Shaders::ProjectionView(glm::mat4 projection, glm::mat4 view) {
	mat[0] = projection;
	mat[1] = view;
	mat[2] = projection * view;
	glBindBuffer(GL_UNIFORM_BUFFER, UBO_matrix);
	glBufferSubData(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), mat);
	glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO_matrix, 0, 3 * sizeof(glm::mat4));
}

void Shaders::set_float(const char* identifier, GLfloat value) {
	GLuint loc = glGetUniformLocation(program, identifier);
	glUniform1f(loc, value);
	check_gl_error;
}

void Shaders::set_int(const char* identifier, GLint value) {
	GLuint loc = glGetUniformLocation(program, identifier);
	glUniform1i(loc, value);
	check_gl_error;
}

void Shaders::set_texture(const char* identifier, Res::Texture* tex, GLuint index) {
	glActiveTexture(GL_TEXTURE0 + index);
	glBindTexture(GL_TEXTURE_2D, tex->texture);
	set_int(identifier, index);
}

Shaders::~Shaders() {
	glDeleteProgram(program);
}
<commit_msg>Add an error check<commit_after>//=============================================================================
// ■ shaders.cpp
//-----------------------------------------------------------------------------
//   VMDE中与着色器有关的全局变量和类都在这里。
//=============================================================================

#include "global.hpp"

Shaders::Shaders() {
}

void Shaders::add_string(GLenum type, const GLchar* source) {
	if (!source) error("source is null");
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	check_shader_compilation(shader, "shader compilation failed");
	shaders[shader_count] = shader;
	shader_count++;
	check_gl_error;
}

void Shaders::add_file(GLenum type, const char* filename) {
	log("adding shader file: %s", filename);
	char* source = Util::read_file(filename);
	add_string(type, source);
	free(source);
}

void Shaders::check_shader_compilation(GLuint shader, const char* msg) {
	GLint success;
	GLchar info_log[512];
	glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
	glGetShaderInfoLog(shader, 512, NULL, info_log);
	if (!success) error("%s:\n%s", msg, info_log);
	log("%s", info_log);
}

void Shaders::check_linkage(GLuint program, const char* msg) {
	GLint success;
	GLchar info_log[512];
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	glGetProgramInfoLog(program, 512, NULL, info_log);
	if (!success) error("%s:\n%s", msg, info_log);
	log("%s", info_log);
}

void Shaders::link_program() {
	// Link shaders
	program = glCreateProgram();
	for (size_t i = 0; i < shader_count; i++) {
		glAttachShader(program, shaders[i]);
	}
	glLinkProgram(program);
	check_linkage(program, "shaders linking failed");
	for (size_t i = 0; i < shader_count; i++) {
		glDeleteShader(shaders[i]);
	}
	check_gl_error;

	GLint loc = glGetUniformBlockIndex(program, "Matrices");
	if (loc == -1) {
		error("No Matrices");
	} else {
		glUniformBlockBinding(program, loc, 0);

		glGenBuffers(1, &UBO_matrix);
		glBindBuffer(GL_UNIFORM_BUFFER, UBO_matrix);
		glBufferData(GL_UNIFORM_BUFFER, 3 * sizeof(glm::mat4), 0, GL_STREAM_DRAW);
		glBindBuffer(GL_UNIFORM_BUFFER, 0);
	}
}

void Shaders::use() {
	glUseProgram(program);
	check_gl_error;
}

void Shaders::ProjectionView(glm::mat4 projection, glm::mat4 view) {
	mat[0] = projection;
	mat[1] = view;
	mat[2] = projection * view;
	glBindBuffer(GL_UNIFORM_BUFFER, UBO_matrix);
	glBufferSubData(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), mat);
	glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO_matrix, 0, 3 * sizeof(glm::mat4));
}

void Shaders::set_float(const char* identifier, GLfloat value) {
	GLuint loc = glGetUniformLocation(program, identifier);
	glUniform1f(loc, value);
	check_gl_error;
}

void Shaders::set_int(const char* identifier, GLint value) {
	GLuint loc = glGetUniformLocation(program, identifier);
	glUniform1i(loc, value);
	check_gl_error;
}

void Shaders::set_texture(const char* identifier, Res::Texture* tex, GLuint index) {
	glActiveTexture(GL_TEXTURE0 + index);
	glBindTexture(GL_TEXTURE_2D, tex->texture);
	set_int(identifier, index);
}

Shaders::~Shaders() {
	glDeleteProgram(program);
}
<|endoftext|>


<commit_before>/**
\file
\brief Main header file for dsb::util.
*/
#ifndef DSB_UTIL_HPP
#define DSB_UTIL_HPP

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "dsb/config.h"
#include "boost/filesystem/path.hpp"
#include "boost/noncopyable.hpp"

namespace dsb
{

/// Misc. utilities (i.e., stuff that didn't really fit anywhere else).
namespace util
{

/// Encodes a 16-bit unsigned integer using little-endian byte order.
void EncodeUint16(uint16_t source, char target[2]);

/// Encodes a 32-bit unsigned integer using little-endian byte order.
void EncodeUint32(uint32_t source, char target[4]);

/// Decodes a 16-bit unsigned integer using little-endian byte order.
uint16_t DecodeUint16(const char source[2]);

/// Decodes a 32-bit unsigned integer using little-endian byte order.
uint32_t DecodeUint32(const char source[4]);

/// Returns a string that contains a random UUID.
std::string RandomUUID();

/**
\brief  Creates a random string.

This creates a string of the given size by randomly selecting characters from
`charSet`, which must be a null-terminated string.

\throws std::invalid_argument
    If `charSet` is null or empty.
*/
std::string RandomString(size_t size, const char* charSet);

/**
\brief  Returns the current UTC time in the ISO 8601 "basic" format.

This returns a string on the form `yyyymmddThhmmssZ` (where the lower-case
letters represent the date/time numbers).
*/
std::string Timestamp();

/**
\brief  Moves a value, replacing it with another one.

This function works just like `std::move`, except that it only works on lvalues
and assigns an explicit value to the variable which is being moved from.  This
is inefficient for types that provide move semantics (`std::move` should be used
for those), but useful for e.g. built-in types.
*/
template<typename T1, typename T2>
T1 MoveAndReplace(T1& variable, const T2& replacement)
{
    auto tmp = std::move(variable);
    variable = replacement;
    return std::move(tmp);
}

/**
\brief  Overload of MoveAndReplace() that replaces `variable` with a
        default-constructed value.
*/
template<typename T>
T MoveAndReplace(T& variable)
{
    return MoveAndReplace(variable, T());
}

/**
\brief  Calls the given function(-like object), but only after swapping it with
        a default-constructed one.

This is useful for function objects that may only be called once, such as
one-shot callbacks.

`LastCall(f, x)` is equivalent to the following:
~~~{.cpp}
F tmp;
swap(f, tmp);
tmp(x);
~~~
Thus, `f` will be left in its default-constructed state even if it throws.
(However, if the default constructor throws in the first line, `f` will
never be called at all.)
*/
template<typename F>
void LastCall(F& f)
{
    F tmp;
    swap(f, tmp);
    tmp();
}

template<typename F, typename A0>
void LastCall(F& f, A0&& a0)
{
    F tmp;
    swap(f, tmp);
    tmp(std::forward<A0>(a0));
}

template<typename Action>
class ScopeGuard : boost::noncopyable
{
public:
    explicit ScopeGuard(Action action) : m_active(true), m_action(action) { }

    ScopeGuard(ScopeGuard&& other)
        : m_active(MoveAndReplace(other.m_active, false)),
          m_action(std::move(other.m_action))
    { }

    ScopeGuard& operator=(ScopeGuard&& other)
    {
        m_active = MoveAndReplace(other.m_active, false);
        m_action = std::move(other.m_action);
    }

    ~ScopeGuard() { if (m_active) m_action(); }

private:
    bool m_active;
    Action m_action;
};

/**
\brief  Scope guard.

This function creates a generic RAII object that will execute a user-defined
action on scope exit.
~~~{.cpp}
void Foo()
{
    // DoSomething() will always be called before Foo() returns.
    auto cleanup = OnScopeExit([]() { DoSomething(); });
    // ...
}
~~~
*/
template<typename Action>
ScopeGuard<Action> OnScopeExit(Action action) { return ScopeGuard<Action>(action); }

/**
\brief  An RAII object that creates a unique directory on construction
        and recursively deletes it again on destruction.
*/
class TempDir
{
public:
    /**
    \brief  Creates a new temporary directory.

    The name of the new directory will be randomly generated, and there are
    three options of where it will be created, depending on the value of
    `parent`.  In the following, `temp` refers to a directory suitable for
    temporary files under the conventions of the operating system (e.g. `/tmp`
    under UNIX-like systems), and `name` refers to the randomly generated
    name mentioned above.

      - If `parent` is empty: `temp/name`
      - If `parent` is relative: `temp/parent/name`
      - If `parent` is absolute: `parent/name`
    */
    explicit TempDir(
        const boost::filesystem::path& parent = boost::filesystem::path());

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

    /**
    \brief  Move constructor.

    Ownership of the directory is transferred from `other` to `this`.
    Afterwards, `other` no longer refers to any directory, meaning that
    `other.Path()` will return an empty path, and its destructor will not
    perform any filesystem operations.
    */
    TempDir(TempDir&& other) DSB_NOEXCEPT;

    /// Move assignment operator. See TempDir(TempDir&&) for semantics.
    TempDir& operator=(TempDir&&) DSB_NOEXCEPT;

    /// Destructor.  Recursively deletes the directory.
    ~TempDir() DSB_NOEXCEPT;

    /// Returns the path to the directory.
    const boost::filesystem::path& Path() const;

private:
    void DeleteNoexcept() DSB_NOEXCEPT;

    boost::filesystem::path m_path;
};

/**
\brief  Starts a new process.

Windows warning: This function only supports a very limited form of argument
quoting.  The elements of args may contain spaces, but no quotation marks or
other characters that are considered "special" in a Windows command line.
*/
void SpawnProcess(
    const std::string& program,
    const std::vector<std::string>& args);

/**
\brief  Returns the path of the current executable.
\throws std::runtime_error if the path could for some reason not be determined.
*/
boost::filesystem::path ThisExePath();

}}      // namespace
#endif  // header guard
<commit_msg>Allow any number of arguments in LastCall<commit_after>/**
\file
\brief Main header file for dsb::util.
*/
#ifndef DSB_UTIL_HPP
#define DSB_UTIL_HPP

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "dsb/config.h"
#include "boost/filesystem/path.hpp"
#include "boost/noncopyable.hpp"

namespace dsb
{

/// Misc. utilities (i.e., stuff that didn't really fit anywhere else).
namespace util
{

/// Encodes a 16-bit unsigned integer using little-endian byte order.
void EncodeUint16(uint16_t source, char target[2]);

/// Encodes a 32-bit unsigned integer using little-endian byte order.
void EncodeUint32(uint32_t source, char target[4]);

/// Decodes a 16-bit unsigned integer using little-endian byte order.
uint16_t DecodeUint16(const char source[2]);

/// Decodes a 32-bit unsigned integer using little-endian byte order.
uint32_t DecodeUint32(const char source[4]);

/// Returns a string that contains a random UUID.
std::string RandomUUID();

/**
\brief  Creates a random string.

This creates a string of the given size by randomly selecting characters from
`charSet`, which must be a null-terminated string.

\throws std::invalid_argument
    If `charSet` is null or empty.
*/
std::string RandomString(size_t size, const char* charSet);

/**
\brief  Returns the current UTC time in the ISO 8601 "basic" format.

This returns a string on the form `yyyymmddThhmmssZ` (where the lower-case
letters represent the date/time numbers).
*/
std::string Timestamp();

/**
\brief  Moves a value, replacing it with another one.

This function works just like `std::move`, except that it only works on lvalues
and assigns an explicit value to the variable which is being moved from.  This
is inefficient for types that provide move semantics (`std::move` should be used
for those), but useful for e.g. built-in types.
*/
template<typename T1, typename T2>
T1 MoveAndReplace(T1& variable, const T2& replacement)
{
    auto tmp = std::move(variable);
    variable = replacement;
    return std::move(tmp);
}

/**
\brief  Overload of MoveAndReplace() that replaces `variable` with a
        default-constructed value.
*/
template<typename T>
T MoveAndReplace(T& variable)
{
    return MoveAndReplace(variable, T());
}

/**
\brief  Calls the given function(-like object), but only after swapping it with
        a default-constructed one.

This is useful for function objects that may only be called once, such as
one-shot callbacks.

`LastCall(f, x)` is equivalent to the following:
~~~{.cpp}
F tmp;
swap(f, tmp);
tmp(x);
~~~
Thus, `f` will be left in its default-constructed state even if it throws.
(However, if the default constructor throws in the first line, `f` will
never be called at all.)
*/
template<typename F>
void LastCall(F& f)
{
    F tmp;
    swap(f, tmp);
    tmp();
}

template<typename F, typename... Args>
void LastCall(F& f, Args&&... args)
{
    F tmp;
    swap(f, tmp);
    tmp(std::forward<Args>(args)...);
}

template<typename Action>
class ScopeGuard : boost::noncopyable
{
public:
    explicit ScopeGuard(Action action) : m_active(true), m_action(action) { }

    ScopeGuard(ScopeGuard&& other)
        : m_active(MoveAndReplace(other.m_active, false)),
          m_action(std::move(other.m_action))
    { }

    ScopeGuard& operator=(ScopeGuard&& other)
    {
        m_active = MoveAndReplace(other.m_active, false);
        m_action = std::move(other.m_action);
    }

    ~ScopeGuard() { if (m_active) m_action(); }

private:
    bool m_active;
    Action m_action;
};

/**
\brief  Scope guard.

This function creates a generic RAII object that will execute a user-defined
action on scope exit.
~~~{.cpp}
void Foo()
{
    // DoSomething() will always be called before Foo() returns.
    auto cleanup = OnScopeExit([]() { DoSomething(); });
    // ...
}
~~~
*/
template<typename Action>
ScopeGuard<Action> OnScopeExit(Action action) { return ScopeGuard<Action>(action); }

/**
\brief  An RAII object that creates a unique directory on construction
        and recursively deletes it again on destruction.
*/
class TempDir
{
public:
    /**
    \brief  Creates a new temporary directory.

    The name of the new directory will be randomly generated, and there are
    three options of where it will be created, depending on the value of
    `parent`.  In the following, `temp` refers to a directory suitable for
    temporary files under the conventions of the operating system (e.g. `/tmp`
    under UNIX-like systems), and `name` refers to the randomly generated
    name mentioned above.

      - If `parent` is empty: `temp/name`
      - If `parent` is relative: `temp/parent/name`
      - If `parent` is absolute: `parent/name`
    */
    explicit TempDir(
        const boost::filesystem::path& parent = boost::filesystem::path());

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

    /**
    \brief  Move constructor.

    Ownership of the directory is transferred from `other` to `this`.
    Afterwards, `other` no longer refers to any directory, meaning that
    `other.Path()` will return an empty path, and its destructor will not
    perform any filesystem operations.
    */
    TempDir(TempDir&& other) DSB_NOEXCEPT;

    /// Move assignment operator. See TempDir(TempDir&&) for semantics.
    TempDir& operator=(TempDir&&) DSB_NOEXCEPT;

    /// Destructor.  Recursively deletes the directory.
    ~TempDir() DSB_NOEXCEPT;

    /// Returns the path to the directory.
    const boost::filesystem::path& Path() const;

private:
    void DeleteNoexcept() DSB_NOEXCEPT;

    boost::filesystem::path m_path;
};

/**
\brief  Starts a new process.

Windows warning: This function only supports a very limited form of argument
quoting.  The elements of args may contain spaces, but no quotation marks or
other characters that are considered "special" in a Windows command line.
*/
void SpawnProcess(
    const std::string& program,
    const std::vector<std::string>& args);

/**
\brief  Returns the path of the current executable.
\throws std::runtime_error if the path could for some reason not be determined.
*/
boost::filesystem::path ThisExePath();

}}      // namespace
#endif  // header guard
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QStaticText>
#include <QtGui/QImage>

#include <private/qstatictext_p.h>

// #define DEBUG_SAVE_IMAGE

class tst_QStaticText: public QObject
{
    Q_OBJECT
private slots:
    void init();
    void cleanup();

    void constructionAndDestruction();
    void drawToPoint();
    void drawToRect();
    void setFont();
    void setMaximumSize();
    void prepareToCorrectData();
    void prepareToWrongData();

    void translatedPainter();
    void rotatedPainter();
    void scaledPainter();
    void rotatedScaledAndTranslatedPainter();
    void transformationChanged();
};

void tst_QStaticText::init()
{
}

void tst_QStaticText::cleanup()
{
}

void tst_QStaticText::constructionAndDestruction()
{
    QStaticText text("My text");
}

void tst_QStaticText::drawToPoint()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::drawToRect()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::prepareToCorrectData()
{
    QTransform transform;
    transform.scale(2.0, 2.0);
    transform.rotate(90, Qt::ZAxis);

    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.setTransform(transform);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.setTransform(transform);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.prepare(transform, p.font());
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::prepareToWrongData()
{
    QTransform transform;
    transform.scale(2.0, 2.0);
    transform.rotate(90, Qt::ZAxis);

    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.prepare(transform, p.font());
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setFont()
{
    QFont font = QApplication::font();
    font.setBold(true);
    font.setPointSize(28);

    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.setFont(font);
        p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);

        QStaticText text;
        text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.drawStaticText(0, 0, text);
        p.setFont(font);
        p.drawStaticText(11, 120, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setMaximumSize()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setMaximumSize(QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(30.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QPainter p(&imageDrawStaticText);
        p.rotate(30.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("rotatedPainter_imageDrawText.png");
    imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::scaledPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.scale(2.0, 0.2);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.scale(2.0, 0.2);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedScaledAndTranslatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::transformationChanged()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);

    {
        QPainter p(&imageDrawText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.scale(7.0, 5.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(0, 0, text);

        p.scale(7.0, 5.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("transformationChanged_imageDrawText.png");
    imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

QTEST_MAIN(tst_QStaticText)
#include "tst_qstatictext.moc"
<commit_msg>Test current graphics system + initialize memory<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QStaticText>
#include <QtGui/QImage>

#include <private/qstatictext_p.h>

// #define DEBUG_SAVE_IMAGE

class tst_QStaticText: public QObject
{
    Q_OBJECT
private slots:
    void init();
    void cleanup();

    void constructionAndDestruction();
    void drawToPoint();
    void drawToRect();
    void setFont();
    void setMaximumSize();
    void prepareToCorrectData();
    void prepareToWrongData();

    void translatedPainter();
    void rotatedPainter();
    void scaledPainter();
    void rotatedScaledAndTranslatedPainter();
    void transformationChanged();
};

void tst_QStaticText::init()
{
}

void tst_QStaticText::cleanup()
{
}

void tst_QStaticText::constructionAndDestruction()
{
    QStaticText text("My text");
}

void tst_QStaticText::drawToPoint()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::drawToRect()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::prepareToCorrectData()
{
    QTransform transform;
    transform.scale(2.0, 2.0);
    transform.rotate(90, Qt::ZAxis);

    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.setTransform(transform);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        p.setTransform(transform);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.prepare(transform, p.font());
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::prepareToWrongData()
{
    QTransform transform;
    transform.scale(2.0, 2.0);
    transform.rotate(90, Qt::ZAxis);

    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.prepare(transform, p.font());
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setFont()
{
    QFont font = QApplication::font();
    font.setBold(true);
    font.setPointSize(28);

    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.setFont(font);
        p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);

        QStaticText text;
        text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.drawStaticText(0, 0, text);
        p.setFont(font);
        p.drawStaticText(11, 120, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setMaximumSize()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setMaximumSize(QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translatedPainter()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedPainter()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.rotate(30.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QPainter p(&imageDrawStaticText);
        p.rotate(30.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("rotatedPainter_imageDrawText.png");
    imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::scaledPainter()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.scale(2.0, 0.2);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        p.scale(2.0, 0.2);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedScaledAndTranslatedPainter()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::transformationChanged()
{
    QPixmap imageDrawText(1000, 1000);
    imageDrawText.fill(Qt::white);
    {
        QPainter p(&imageDrawText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.scale(7.0, 5.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QPixmap imageDrawStaticText(1000, 1000);
    imageDrawStaticText.fill(Qt::white);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(0, 0, text);

        p.scale(7.0, 5.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("transformationChanged_imageDrawText.png");
    imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

QTEST_MAIN(tst_QStaticText)
#include "tst_qstatictext.moc"
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QStaticText>
#include <QtGui/QImage>

#include <private/qstatictext_p.h>

// #define DEBUG_SAVE_IMAGE

class tst_QStaticText: public QObject
{
    Q_OBJECT
private slots:
    void init();
    void cleanup();

    void constructionAndDestruction();
    void drawToPoint();
    void drawToRect();
    void setFont();
    void setMaximumSize();

    void translatedPainter();
    void rotatedPainter();
    void scaledPainter();
    void rotatedScaledAndTranslatedPainter();
    void transformationChanged();
    void translationDoesntCauseRelayout();
};

void tst_QStaticText::init()
{
}

void tst_QStaticText::cleanup()
{
}

void tst_QStaticText::constructionAndDestruction()
{
    QStaticText text("My text");
}

void tst_QStaticText::drawToPoint()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::drawToRect()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QFont(), QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setFont()
{
    QFont font = QApplication::font();
    font.setBold(true);
    font.setPointSize(28);

    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.setFont(font);
        p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text;
        text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setFont(font);
        p.drawStaticText(11, 120, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setMaximumSize()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setMaximumSize(QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(30.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QPainter p(&imageDrawStaticText);
        p.rotate(30.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("rotatedPainter_imageDrawText.png");
    imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::scaledPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.scale(2.0, 0.2);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.scale(2.0, 0.2);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedScaledAndTranslatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::transformationChanged()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);

    {
        QPainter p(&imageDrawText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.scale(7.0, 5.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(0, 0, text);

        p.scale(7.0, 5.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("transformationChanged_imageDrawText.png");
    imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translationDoesntCauseRelayout()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.translate(100, 200);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QStaticTextPrivate *textd = QStaticTextPrivate::get(&text);
        glyph_t *glyphPool = textd->glyphPool;
        QFixedPoint *positionPool = textd->positionPool;
        QStaticTextItem *items = textd->items;

        p.drawStaticText(11, 12, text);

        p.translate(100, 200);
        p.drawStaticText(11, 12, text);

        // ###
        // If the layout is recalculated, the data is reallocated. Not a entirely deterministic
        // test, since the memory can be reused.
        QCOMPARE(textd->glyphPool, glyphPool);
        QCOMPARE(textd->positionPool, positionPool);
        QCOMPARE(textd->items, items);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);

}

QTEST_MAIN(tst_QStaticText)
#include "tst_qstatictext.moc"
<commit_msg>Ignore rounding errors in QStaticText test<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used 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.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtGui/QApplication>
#include <QtGui/QPainter>
#include <QtGui/QStaticText>
#include <QtGui/QImage>

#include <private/qstatictext_p.h>

// #define DEBUG_SAVE_IMAGE

class tst_QStaticText: public QObject
{
    Q_OBJECT
private slots:
    void init();
    void cleanup();

    void constructionAndDestruction();
    void drawToPoint();
    void drawToRect();
    void setFont();
    void setMaximumSize();

    void translatedPainter();
    void rotatedPainter();
    void scaledPainter();
    void rotatedScaledAndTranslatedPainter();
    void transformationChanged();
    void translationDoesntCauseRelayout();
};

void tst_QStaticText::init()
{
}

void tst_QStaticText::cleanup()
{
}

void tst_QStaticText::constructionAndDestruction()
{
    QStaticText text("My text");
}

void tst_QStaticText::drawToPoint()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::drawToRect()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QFont(), QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setFont()
{
    QFont font = QApplication::font();
    font.setBold(true);
    font.setPointSize(28);

    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.setFont(font);
        p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text;
        text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setFont(font);
        p.drawStaticText(11, 120, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::setMaximumSize()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        text.setMaximumSize(QSizeF(10, 500));
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(30.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QPainter p(&imageDrawStaticText);
        p.rotate(30.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("rotatedPainter_imageDrawText.png");
    imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::scaledPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.scale(2.0, 0.2);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.scale(2.0, 0.2);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::rotatedScaledAndTranslatedPainter()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(45.0);
        p.scale(0.2, 2.0);
        p.translate(100, 200);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(11, 12, text);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::transformationChanged()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);

    {
        QPainter p(&imageDrawText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.scale(7.0, 5.0);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        p.rotate(33.0);
        p.scale(0.5, 0.7);

        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
        p.drawStaticText(0, 0, text);

        p.scale(7.0, 5.0);
        p.drawStaticText(0, 0, text);
    }

#if defined(DEBUG_SAVE_IMAGE)
    imageDrawText.save("transformationChanged_imageDrawText.png");
    imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png");
#endif

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

void tst_QStaticText::translationDoesntCauseRelayout()
{
    QImage imageDrawText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawText);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        p.translate(100, 200);
        p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
    }

    QImage imageDrawStaticText(1000, 1000, QImage::Format_ARGB32_Premultiplied);
    {
        QPainter p(&imageDrawStaticText);
        QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");

        QStaticTextPrivate *textd = QStaticTextPrivate::get(&text);
        glyph_t *glyphPool = textd->glyphPool;
        QFixedPoint *positionPool = textd->positionPool;
        QStaticTextItem *items = textd->items;

        p.drawStaticText(0, 0, text);

        p.translate(100, 200);
        p.drawStaticText(0, 0, text);

        // ###
        // If the layout is recalculated, the data is reallocated. Not a entirely deterministic
        // test, since the memory can be reused.
        QCOMPARE(textd->glyphPool, glyphPool);
        QCOMPARE(textd->positionPool, positionPool);
        QCOMPARE(textd->items, items);
    }

    QCOMPARE(imageDrawStaticText, imageDrawText);
}

QTEST_MAIN(tst_QStaticText)
#include "tst_qstatictext.moc"
<|endoftext|>