<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 "GrSoftwarePathRenderer.h"
#include "GrPaint.h"
#include "SkPaint.h"
#include "GrRenderTarget.h"
#include "GrContext.h"
#include "SkDraw.h"
#include "SkRasterClip.h"
#include "GrGpu.h"

////////////////////////////////////////////////////////////////////////////////
bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
                                         GrPathFill fill,
                                         const GrDrawTarget* target,
                                         bool antiAlias) const {
    if (!antiAlias || NULL == fContext) {
        // TODO: We could allow the SW path to also handle non-AA paths but
        // this would mean that GrDefaultPathRenderer would never be called
        // (since it appears after the SW renderer in the path renderer
        // chain). Some testing would need to be done r.e. performance
        // and consistency of the resulting images before removing
        // the "!antiAlias" clause from the above test
        return false;
    }

    return true;
}

namespace {

////////////////////////////////////////////////////////////////////////////////
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
    switch (fill) {
        case kWinding_GrPathFill:
            return SkPath::kWinding_FillType;
        case kEvenOdd_GrPathFill:
            return SkPath::kEvenOdd_FillType;
        case kInverseWinding_GrPathFill:
            return SkPath::kInverseWinding_FillType;
        case kInverseEvenOdd_GrPathFill:
            return SkPath::kInverseEvenOdd_FillType;
        default:
            GrCrash("Unexpected fill.");
            return SkPath::kWinding_FillType;
    }
}

////////////////////////////////////////////////////////////////////////////////
// gets device coord bounds of path (not considering the fill) and clip. The
// path bounds will be a subset of the clip bounds. returns false if
// path bounds would be empty.
bool get_path_and_clip_bounds(const GrDrawTarget* target,
                              const SkPath& path,
                              const GrVec* translate,
                              GrIRect* pathBounds,
                              GrIRect* clipBounds) {
    // compute bounds as intersection of rt size, clip, and path
    const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
    if (NULL == rt) {
        return false;
    }
    *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
    const GrClip& clip = target->getClip();
    if (clip.hasConservativeBounds()) {
        clip.getConservativeBounds().roundOut(clipBounds);
        if (!pathBounds->intersect(*clipBounds)) {
            return false;
        }
    } else {
        // pathBounds is currently the rt extent, set clip bounds to that rect.
        *clipBounds = *pathBounds;
    }
    GrRect pathSBounds = path.getBounds();
    if (!pathSBounds.isEmpty()) {
        if (NULL != translate) {
            pathSBounds.offset(*translate);
        }
        target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
                                                        pathSBounds);
        GrIRect pathIBounds;
        pathSBounds.roundOut(&pathIBounds);
        if (!pathBounds->intersect(pathIBounds)) {
            // set the correct path bounds, as this would be used later.
            *pathBounds = pathIBounds;
            return false;
        }
    } else {
        *pathBounds = GrIRect::EmptyIRect();
        return false;
    }
    return true;
}

/*
 * Convert a boolean operation into a transfer mode code
 */
SkXfermode::Mode op_to_mode(SkRegion::Op op) {

    static const SkXfermode::Mode modeMap[] = {
        SkXfermode::kDstOut_Mode,   // kDifference_Op
        SkXfermode::kMultiply_Mode, // kIntersect_Op
        SkXfermode::kSrcOver_Mode,  // kUnion_Op
        SkXfermode::kXor_Mode,      // kXOR_Op
        SkXfermode::kClear_Mode,    // kReverseDifference_Op
        SkXfermode::kSrc_Mode,      // kReplace_Op
    };

    return modeMap[op];
}

}

/**
 * Draw a single rect element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
                          bool antiAlias, GrColor color) {
    SkPaint paint;

    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawRect(clientRect, paint);

    SkSafeUnref(mode);
}

/**
 * Draw a single path element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
                          GrPathFill fill, bool antiAlias, GrColor color) {

    SkPaint paint;
    SkPath tmpPath;
    const SkPath* pathToDraw = &clientPath;
    if (kHairLine_GrPathFill == fill) {
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SK_Scalar1);
    } else {
        paint.setStyle(SkPaint::kFill_Style);
        SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
        if (skfill != pathToDraw->getFillType()) {
            tmpPath = *pathToDraw;
            tmpPath.setFillType(skfill);
            pathToDraw = &tmpPath;
        }
    }
    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawPath(*pathToDraw, paint);

    SkSafeUnref(mode);
}

bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
                          const GrPoint* translate,
                          bool useMatrix) {
    if (useMatrix) {
        fMatrix = fContext->getMatrix();
    } else {
        fMatrix.setIdentity();
    }

    if (NULL != translate) {
        fMatrix.postTranslate(translate->fX, translate->fY);
    }

    fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
                          -pathDevBounds.fTop * SK_Scalar1);
    GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
                                     pathDevBounds.height());

    fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
    if (!fBM.allocPixels()) {
        return false;
    }
    sk_bzero(fBM.getPixels(), fBM.getSafeSize());

    sk_bzero(&fDraw, sizeof(fDraw));
    fRasterClip.setRect(bounds);
    fDraw.fRC    = &fRasterClip;
    fDraw.fClip  = &fRasterClip.bwRgn();
    fDraw.fMatrix = &fMatrix;
    fDraw.fBitmap = &fBM;
    return true;
}

/**
 * Get a texture (from the texture cache) of the correct size & format
 */
bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) {
    GrTextureDesc desc;
    desc.fWidth = fBM.width();
    desc.fHeight = fBM.height();
    desc.fConfig = kAlpha_8_GrPixelConfig;

    tex->set(fContext, desc);
    GrTexture* texture = tex->texture();

    if (NULL == texture) {
        return false;
    }

    return true;
}

/**
 * Move the result of the software mask generation back to the gpu
 */
void GrSWMaskHelper::toTexture(GrTexture *texture, bool clearToWhite) {
    SkAutoLockPixels alp(fBM);

    // The destination texture is almost always larger than "fBM". Clear
    // it appropriately so we don't get mask artifacts outside of the path's
    // bounding box

    // "texture" needs to be installed as the render target for the clear
    // and the texture upload but cannot remain the render target upon
    // returned. Callers typically use it as a texture and it would then
    // be both source and dest.
    GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(),
                                              texture->asRenderTarget());

    if (clearToWhite) {
        fContext->getGpu()->clear(NULL, SK_ColorWHITE);
    } else {
        fContext->getGpu()->clear(NULL, 0x00000000);
    }

    texture->writePixels(0, 0, fBM.width(), fBM.height(),
                         kAlpha_8_GrPixelConfig,
                         fBM.getPixels(), fBM.rowBytes());
}

namespace {
////////////////////////////////////////////////////////////////////////////////
/**
 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
 * scratch texture.
 */
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
                                  const GrIRect& pathDevBounds,
                                  GrPathFill fill,
                                  GrContext* context,
                                  const GrPoint* translate,
                                  GrAutoScratchTexture* tex,
                                  bool antiAlias) {
    GrSWMaskHelper helper(context);

    if (!helper.init(pathDevBounds, translate, true)) {
        return false;
    }

    helper.draw(clientPath, SkRegion::kReplace_Op,
                fill, antiAlias, SK_ColorWHITE);

    if (!helper.getTexture(tex)) {
        return false;
    }

    helper.toTexture(tex->texture(), false);

    return true;
}

////////////////////////////////////////////////////////////////////////////////
void draw_around_inv_path(GrDrawTarget* target,
                          GrDrawState::StageMask stageMask,
                          const GrIRect& clipBounds,
                          const GrIRect& pathBounds) {
    GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
    GrRect rect;
    if (clipBounds.fTop < pathBounds.fTop) {
        rect.iset(clipBounds.fLeft, clipBounds.fTop,
                    clipBounds.fRight, pathBounds.fTop);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fLeft < pathBounds.fLeft) {
        rect.iset(clipBounds.fLeft, pathBounds.fTop,
                    pathBounds.fLeft, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fRight > pathBounds.fRight) {
        rect.iset(pathBounds.fRight, pathBounds.fTop,
                    clipBounds.fRight, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fBottom > pathBounds.fBottom) {
        rect.iset(clipBounds.fLeft, pathBounds.fBottom,
                    clipBounds.fRight, clipBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
}

}

////////////////////////////////////////////////////////////////////////////////
// return true on success; false on failure
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
                                        GrPathFill fill,
                                        const GrVec* translate,
                                        GrDrawTarget* target,
                                        GrDrawState::StageMask stageMask,
                                        bool antiAlias) {

    if (NULL == fContext) {
        return false;
    }

    GrAutoScratchTexture ast;
    GrIRect pathBounds, clipBounds;
    if (!get_path_and_clip_bounds(target, path, translate,
                                  &pathBounds, &clipBounds)) {
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }
    if (sw_draw_path_to_mask_texture(path, pathBounds,
                                     fill, fContext,
                                     translate, &ast, antiAlias)) {
        SkAutoTUnref<GrTexture> texture(ast.detach());
        GrAssert(NULL != texture);
        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
        enum {
            // the SW path renderer shares this stage with glyph
            // rendering (kGlyphMaskStage in GrBatchedTextContext)
            kPathMaskStage = GrPaint::kTotalStages,
        };
        GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage));
        target->drawState()->setTexture(kPathMaskStage, texture);
        target->drawState()->sampler(kPathMaskStage)->reset();
        GrScalar w = GrIntToScalar(pathBounds.width());
        GrScalar h = GrIntToScalar(pathBounds.height());
        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                         h / texture->height());

        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
        srcRects[kPathMaskStage] = &maskRect;
        stageMask |= 1 << kPathMaskStage;
        GrRect dstRect = GrRect::MakeLTRB(
                              SK_Scalar1* pathBounds.fLeft,
                              SK_Scalar1* pathBounds.fTop,
                              SK_Scalar1* pathBounds.fRight,
                              SK_Scalar1* pathBounds.fBottom);
        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
        target->drawState()->setTexture(kPathMaskStage, NULL);
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }

    return false;
}
<commit_msg>Reverting r4319<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 "GrSoftwarePathRenderer.h"
#include "GrPaint.h"
#include "SkPaint.h"
#include "GrRenderTarget.h"
#include "GrContext.h"
#include "SkDraw.h"
#include "SkRasterClip.h"
#include "GrGpu.h"

////////////////////////////////////////////////////////////////////////////////
bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
                                         GrPathFill fill,
                                         const GrDrawTarget* target,
                                         bool antiAlias) const {
    if (!antiAlias || NULL == fContext) {
        // TODO: We could allow the SW path to also handle non-AA paths but
        // this would mean that GrDefaultPathRenderer would never be called
        // (since it appears after the SW renderer in the path renderer
        // chain). Some testing would need to be done r.e. performance
        // and consistency of the resulting images before removing
        // the "!antiAlias" clause from the above test
        return false;
    }

    return true;
}

namespace {

////////////////////////////////////////////////////////////////////////////////
SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
    switch (fill) {
        case kWinding_GrPathFill:
            return SkPath::kWinding_FillType;
        case kEvenOdd_GrPathFill:
            return SkPath::kEvenOdd_FillType;
        case kInverseWinding_GrPathFill:
            return SkPath::kInverseWinding_FillType;
        case kInverseEvenOdd_GrPathFill:
            return SkPath::kInverseEvenOdd_FillType;
        default:
            GrCrash("Unexpected fill.");
            return SkPath::kWinding_FillType;
    }
}

////////////////////////////////////////////////////////////////////////////////
// gets device coord bounds of path (not considering the fill) and clip. The
// path bounds will be a subset of the clip bounds. returns false if
// path bounds would be empty.
bool get_path_and_clip_bounds(const GrDrawTarget* target,
                              const SkPath& path,
                              const GrVec* translate,
                              GrIRect* pathBounds,
                              GrIRect* clipBounds) {
    // compute bounds as intersection of rt size, clip, and path
    const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
    if (NULL == rt) {
        return false;
    }
    *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
    const GrClip& clip = target->getClip();
    if (clip.hasConservativeBounds()) {
        clip.getConservativeBounds().roundOut(clipBounds);
        if (!pathBounds->intersect(*clipBounds)) {
            return false;
        }
    } else {
        // pathBounds is currently the rt extent, set clip bounds to that rect.
        *clipBounds = *pathBounds;
    }
    GrRect pathSBounds = path.getBounds();
    if (!pathSBounds.isEmpty()) {
        if (NULL != translate) {
            pathSBounds.offset(*translate);
        }
        target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
                                                        pathSBounds);
        GrIRect pathIBounds;
        pathSBounds.roundOut(&pathIBounds);
        if (!pathBounds->intersect(pathIBounds)) {
            // set the correct path bounds, as this would be used later.
            *pathBounds = pathIBounds;
            return false;
        }
    } else {
        *pathBounds = GrIRect::EmptyIRect();
        return false;
    }
    return true;
}

/*
 * Convert a boolean operation into a transfer mode code
 */
SkXfermode::Mode op_to_mode(SkRegion::Op op) {

    static const SkXfermode::Mode modeMap[] = {
        SkXfermode::kDstOut_Mode,   // kDifference_Op
        SkXfermode::kMultiply_Mode, // kIntersect_Op
        SkXfermode::kSrcOver_Mode,  // kUnion_Op
        SkXfermode::kXor_Mode,      // kXOR_Op
        SkXfermode::kClear_Mode,    // kReverseDifference_Op
        SkXfermode::kSrc_Mode,      // kReplace_Op
    };

    return modeMap[op];
}

}

/**
 * Draw a single rect element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
                          bool antiAlias, GrColor color) {
    SkPaint paint;

    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawRect(clientRect, paint);

    SkSafeUnref(mode);
}

/**
 * Draw a single path element of the clip stack into the accumulation bitmap
 */
void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
                          GrPathFill fill, bool antiAlias, GrColor color) {

    SkPaint paint;
    SkPath tmpPath;
    const SkPath* pathToDraw = &clientPath;
    if (kHairLine_GrPathFill == fill) {
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SK_Scalar1);
    } else {
        paint.setStyle(SkPaint::kFill_Style);
        SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
        if (skfill != pathToDraw->getFillType()) {
            tmpPath = *pathToDraw;
            tmpPath.setFillType(skfill);
            pathToDraw = &tmpPath;
        }
    }
    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));

    paint.setXfermode(mode);
    paint.setAntiAlias(antiAlias);
    paint.setColor(color);

    fDraw.drawPath(*pathToDraw, paint);

    SkSafeUnref(mode);
}

bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
                          const GrPoint* translate,
                          bool useMatrix) {
    if (useMatrix) {
        fMatrix = fContext->getMatrix();
    } else {
        fMatrix.setIdentity();
    }

    if (NULL != translate) {
        fMatrix.postTranslate(translate->fX, translate->fY);
    }

    fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
                          -pathDevBounds.fTop * SK_Scalar1);
    GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
                                     pathDevBounds.height());

    fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
    if (!fBM.allocPixels()) {
        return false;
    }
    sk_bzero(fBM.getPixels(), fBM.getSafeSize());

    sk_bzero(&fDraw, sizeof(fDraw));
    fRasterClip.setRect(bounds);
    fDraw.fRC    = &fRasterClip;
    fDraw.fClip  = &fRasterClip.bwRgn();
    fDraw.fMatrix = &fMatrix;
    fDraw.fBitmap = &fBM;
    return true;
}

/**
 * Get a texture (from the texture cache) of the correct size & format
 */
bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) {
    GrTextureDesc desc;
    desc.fWidth = fBM.width();
    desc.fHeight = fBM.height();
    desc.fConfig = kAlpha_8_GrPixelConfig;

    tex->set(fContext, desc);
    GrTexture* texture = tex->texture();

    if (NULL == texture) {
        return false;
    }

    return true;
}

/**
 * Move the result of the software mask generation back to the gpu
 */
void GrSWMaskHelper::toTexture(GrTexture *texture, bool clearToWhite) {
    SkAutoLockPixels alp(fBM);

    // The destination texture is almost always larger than "fBM". Clear
    // it appropriately so we don't get mask artifacts outside of the path's
    // bounding box

    // "texture" needs to be installed as the render target for the clear
    // and the texture upload but cannot remain the render target upon
    // returned. Callers typically use it as a texture and it would then
    // be both source and dest.
    GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(),
                                              texture->asRenderTarget());

    if (clearToWhite) {
        fContext->getGpu()->clear(NULL, SK_ColorWHITE);
    } else {
        fContext->getGpu()->clear(NULL, 0x00000000);
    }

    texture->writePixels(0, 0, fBM.width(), fBM.height(),
                         kAlpha_8_GrPixelConfig,
                         fBM.getPixels(), fBM.rowBytes());
}

namespace {
////////////////////////////////////////////////////////////////////////////////
/**
 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
 * scratch texture.
 */
bool sw_draw_path_to_mask_texture(const SkPath& clientPath,
                                  const GrIRect& pathDevBounds,
                                  GrPathFill fill,
                                  GrContext* context,
                                  const GrPoint* translate,
                                  GrAutoScratchTexture* tex,
                                  bool antiAlias) {
    GrSWMaskHelper helper(context);

    if (!helper.init(pathDevBounds, translate, true)) {
        return false;
    }

    helper.draw(clientPath, SkRegion::kReplace_Op,
                fill, antiAlias, SK_ColorWHITE);

    if (!helper.getTexture(tex)) {
        return false;
    }

    helper.toTexture(tex->texture(), false);

    return true;
}

////////////////////////////////////////////////////////////////////////////////
void draw_around_inv_path(GrDrawTarget* target,
                          GrDrawState::StageMask stageMask,
                          const GrIRect& clipBounds,
                          const GrIRect& pathBounds) {
    GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
    GrRect rect;
    if (clipBounds.fTop < pathBounds.fTop) {
        rect.iset(clipBounds.fLeft, clipBounds.fTop,
                    clipBounds.fRight, pathBounds.fTop);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fLeft < pathBounds.fLeft) {
        rect.iset(clipBounds.fLeft, pathBounds.fTop,
                    pathBounds.fLeft, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fRight > pathBounds.fRight) {
        rect.iset(pathBounds.fRight, pathBounds.fTop,
                    clipBounds.fRight, pathBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
    if (clipBounds.fBottom > pathBounds.fBottom) {
        rect.iset(clipBounds.fLeft, pathBounds.fBottom,
                    clipBounds.fRight, clipBounds.fBottom);
        target->drawSimpleRect(rect, NULL, stageMask);
    }
}

}

////////////////////////////////////////////////////////////////////////////////
// return true on success; false on failure
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
                                        GrPathFill fill,
                                        const GrVec* translate,
                                        GrDrawTarget* target,
                                        GrDrawState::StageMask stageMask,
                                        bool antiAlias) {

    if (NULL == fContext) {
        return false;
    }

    GrAutoScratchTexture ast;
    GrIRect pathBounds, clipBounds;
    if (!get_path_and_clip_bounds(target, path, translate,
                                  &pathBounds, &clipBounds)) {
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }
    if (sw_draw_path_to_mask_texture(path, pathBounds,
                                     fill, fContext,
                                     translate, &ast, antiAlias)) {
#if 1
        GrTexture* texture = ast.texture();
#else
        SkAutoTUnref<GrTexture> texture(ast.detach());
#endif
        GrAssert(NULL != texture);
        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
        enum {
            // the SW path renderer shares this stage with glyph
            // rendering (kGlyphMaskStage in GrBatchedTextContext)
            kPathMaskStage = GrPaint::kTotalStages,
        };
        GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage));
        target->drawState()->setTexture(kPathMaskStage, texture);
        target->drawState()->sampler(kPathMaskStage)->reset();
        GrScalar w = GrIntToScalar(pathBounds.width());
        GrScalar h = GrIntToScalar(pathBounds.height());
        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                         h / texture->height());

        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
        srcRects[kPathMaskStage] = &maskRect;
        stageMask |= 1 << kPathMaskStage;
        GrRect dstRect = GrRect::MakeLTRB(
                              SK_Scalar1* pathBounds.fLeft,
                              SK_Scalar1* pathBounds.fTop,
                              SK_Scalar1* pathBounds.fRight,
                              SK_Scalar1* pathBounds.fBottom);
        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
        target->drawState()->setTexture(kPathMaskStage, NULL);
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }

    return false;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2005-2017 by the FIFE team                              *
 *   http://www.fifengine.net                                              *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes
#if defined( WIN32 )
#include <windows.h>
#include <SDL.h>
#endif

#if defined( __unix__ )
#include <X11/Xcursor/Xcursor.h>
#endif

// 3rd party library includes

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "util/structures/rect.h"
#include "util/time/timemanager.h"
#include "util/log/logger.h"
#include "video/imagemanager.h"

#include "animation.h"
#include "image.h"
#include "renderbackend.h"
#include "cursor.h"

#if defined( WIN32 )

// From SDL_sysmouse.c
struct WMcursor {
	HCURSOR curs;
#ifndef _WIN32_WCE
	Uint8 *ands;
	Uint8 *xors;
#endif
};

#endif

#if defined( __unix__ )

// Stops the compiler from confusing it with FIFE:Cursor
typedef Cursor XCursor;

// From SDL_x11mouse.c
struct WMcursor {
	Cursor x_cursor;
};

#endif

namespace FIFE {
	/** Logger to use for this source file.
	 *  @relates Logger
	 */
	static Logger _log(LM_GUI); //@todo We should have a log module for cursor

	Cursor::Cursor(RenderBackend* renderbackend):
		m_cursor_id(NC_ARROW),
		m_cursor_type(CURSOR_NATIVE),
		m_drag_type(CURSOR_NONE),
		m_native_cursor(NULL),
		m_renderbackend(renderbackend),
		m_animtime(0),
		m_drag_animtime(0),
		m_drag_offset_x(0),
		m_drag_offset_y(0),
		m_mx(0),
		m_my(0),
		m_timemanager(TimeManager::instance()),
		m_invalidated(false) {
		assert(m_timemanager);
		set(m_cursor_id);
	}

	void Cursor::set(uint32_t cursor_id) {
		m_cursor_type = CURSOR_NATIVE;

		if (!SDL_ShowCursor(1)) {
			SDL_PumpEvents();
		}
		setNativeCursor(cursor_id);

		m_cursor_image.reset();
		m_cursor_animation.reset();
	}

	void Cursor::set(ImagePtr image) {
		assert(image != 0);

		m_cursor_image = image;
		m_cursor_type = CURSOR_IMAGE;

		if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}

		m_cursor_id = NC_ARROW;
		m_cursor_animation.reset();
	}

	void Cursor::set(AnimationPtr anim) {
		assert(anim != 0);

		m_cursor_animation = anim;
		m_cursor_type = CURSOR_ANIMATION;

		if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}
		m_animtime = m_timemanager->getTime();

		m_cursor_id = NC_ARROW;
		m_cursor_image.reset();
	}

	void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(image != 0);

		m_cursor_drag_image = image;
		m_drag_type = CURSOR_IMAGE;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_cursor_drag_animation.reset();
	}

	void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(anim != 0);

		m_cursor_drag_animation = anim;
		m_drag_type = CURSOR_ANIMATION;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_drag_animtime = m_timemanager->getTime();

		m_cursor_drag_image.reset();
	}

	void Cursor::resetDrag() {
		m_drag_type = CURSOR_NONE;

		m_drag_animtime = 0;
		m_drag_offset_x = 0;
		m_drag_offset_y = 0;

		m_cursor_drag_animation.reset();
		m_cursor_drag_image.reset();
	}

    void Cursor::setPosition(uint32_t x, uint32_t y) {
		m_mx = x;
		m_my = y;
		SDL_WarpMouseInWindow(RenderBackend::instance()->getWindow(), m_mx, m_my);
	}

    void Cursor::getPosition(int32_t* x, int32_t* y) {
        *x = m_mx;
        *y = m_my;
    }

	void Cursor::invalidate() {
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
			m_native_cursor = NULL;

			m_invalidated = true;
		}
	}

	void Cursor::draw() {
		if (m_invalidated) {
			if (m_cursor_type != CURSOR_ANIMATION || m_cursor_type == CURSOR_IMAGE ) {
				set(m_cursor_id);
			}

			m_invalidated = false;
		}

		SDL_GetMouseState(&m_mx, &m_my);
		if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
			return;
		}

		// render possible drag image
		ImagePtr img;
		if (m_drag_type == CURSOR_IMAGE) {
			img = m_cursor_drag_image;
		}
		else if (m_drag_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_drag_animtime) % m_cursor_drag_animation->getDuration();
			img = m_cursor_drag_animation->getFrameByTimestamp(animtime);
		}

		if (img != 0) {
			Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}

		ImagePtr img2;
		// render possible cursor image
		if (m_cursor_type == CURSOR_IMAGE) {
			img2 = m_cursor_image;
		}
		else if (m_cursor_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
			img2 = m_cursor_animation->getFrameByTimestamp(animtime);
		}

		if (img2 != 0) {
			Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img2->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}
	}

	uint32_t Cursor::getNativeId(uint32_t cursor_id) {
		switch (cursor_id) {
			case NC_ARROW:
				return SDL_SYSTEM_CURSOR_ARROW;
			case NC_IBEAM:
				return SDL_SYSTEM_CURSOR_IBEAM;
			case NC_WAIT:
				return SDL_SYSTEM_CURSOR_WAIT;
			case NC_CROSS:
				return SDL_SYSTEM_CURSOR_CROSSHAIR;
			case NC_WAITARROW:
				return SDL_SYSTEM_CURSOR_WAITARROW;
			case NC_RESIZENWSE:
				return SDL_SYSTEM_CURSOR_SIZENWSE;
			case NC_RESIZENESW:
				return SDL_SYSTEM_CURSOR_SIZENESW;
			case NC_RESIZEWE:
				return SDL_SYSTEM_CURSOR_SIZEWE;
			case NC_RESIZENS:
				return SDL_SYSTEM_CURSOR_SIZENS;
			case NC_RESIZEALL:
				return SDL_SYSTEM_CURSOR_SIZEALL;
			case NC_NO:
				return SDL_SYSTEM_CURSOR_NO;
			case NC_HAND:
				return SDL_SYSTEM_CURSOR_HAND;
		}
		return cursor_id;
	}

	void Cursor::setNativeCursor(uint32_t cursor_id) {
		cursor_id = getNativeId(cursor_id);
		SDL_Cursor* cursor = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(cursor_id));
		if (!cursor) {
			FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
			return;
		}
		m_native_cursor = cursor;
		SDL_SetCursor(cursor);
	}
}
<commit_msg>Removed leftover stuff from Cursor. Refs #991 I see no reason to keep XCursor and WMCursor around. Cursor only needs SDL.<commit_after>/***************************************************************************
 *   Copyright (C) 2005-2017 by the FIFE team                              *
 *   http://www.fifengine.net                                              *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes

// 3rd party library includes
#include <SDL.h>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "util/structures/rect.h"
#include "util/time/timemanager.h"
#include "util/log/logger.h"
#include "video/imagemanager.h"

#include "animation.h"
#include "image.h"
#include "renderbackend.h"
#include "cursor.h"

namespace FIFE {
	/** Logger to use for this source file.
	 *  @relates Logger
	 */
	static Logger _log(LM_GUI); //@todo We should have a log module for cursor

	Cursor::Cursor(RenderBackend* renderbackend):
		m_cursor_id(NC_ARROW),
		m_cursor_type(CURSOR_NATIVE),
		m_drag_type(CURSOR_NONE),
		m_native_cursor(NULL),
		m_renderbackend(renderbackend),
		m_animtime(0),
		m_drag_animtime(0),
		m_drag_offset_x(0),
		m_drag_offset_y(0),
		m_mx(0),
		m_my(0),
		m_timemanager(TimeManager::instance()),
		m_invalidated(false) {
		assert(m_timemanager);
		set(m_cursor_id);
	}

	void Cursor::set(uint32_t cursor_id) {
		m_cursor_type = CURSOR_NATIVE;

		if (!SDL_ShowCursor(1)) {
			SDL_PumpEvents();
		}
		setNativeCursor(cursor_id);

		m_cursor_image.reset();
		m_cursor_animation.reset();
	}

	void Cursor::set(ImagePtr image) {
		assert(image != 0);

		m_cursor_image = image;
		m_cursor_type = CURSOR_IMAGE;

		if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}

		m_cursor_id = NC_ARROW;
		m_cursor_animation.reset();
	}

	void Cursor::set(AnimationPtr anim) {
		assert(anim != 0);

		m_cursor_animation = anim;
		m_cursor_type = CURSOR_ANIMATION;

		if (SDL_ShowCursor(0)) {
			SDL_PumpEvents();
		}
		m_animtime = m_timemanager->getTime();

		m_cursor_id = NC_ARROW;
		m_cursor_image.reset();
	}

	void Cursor::setDrag(ImagePtr image, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(image != 0);

		m_cursor_drag_image = image;
		m_drag_type = CURSOR_IMAGE;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_cursor_drag_animation.reset();
	}

	void Cursor::setDrag(AnimationPtr anim, int32_t drag_offset_x, int32_t drag_offset_y) {
		assert(anim != 0);

		m_cursor_drag_animation = anim;
		m_drag_type = CURSOR_ANIMATION;
		m_drag_offset_x = drag_offset_x;
		m_drag_offset_y = drag_offset_y;

		m_drag_animtime = m_timemanager->getTime();

		m_cursor_drag_image.reset();
	}

	void Cursor::resetDrag() {
		m_drag_type = CURSOR_NONE;

		m_drag_animtime = 0;
		m_drag_offset_x = 0;
		m_drag_offset_y = 0;

		m_cursor_drag_animation.reset();
		m_cursor_drag_image.reset();
	}

    void Cursor::setPosition(uint32_t x, uint32_t y) {
		m_mx = x;
		m_my = y;
		SDL_WarpMouseInWindow(RenderBackend::instance()->getWindow(), m_mx, m_my);
	}

    void Cursor::getPosition(int32_t* x, int32_t* y) {
        *x = m_mx;
        *y = m_my;
    }

	void Cursor::invalidate() {
		if (m_native_cursor != NULL) {
			SDL_FreeCursor(m_native_cursor);
			m_native_cursor = NULL;

			m_invalidated = true;
		}
	}

	void Cursor::draw() {
		if (m_invalidated) {
			if (m_cursor_type != CURSOR_ANIMATION || m_cursor_type == CURSOR_IMAGE ) {
				set(m_cursor_id);
			}

			m_invalidated = false;
		}

		SDL_GetMouseState(&m_mx, &m_my);
		if ((m_cursor_type == CURSOR_NATIVE) && (m_drag_type == CURSOR_NONE)) {
			return;
		}

		// render possible drag image
		ImagePtr img;
		if (m_drag_type == CURSOR_IMAGE) {
			img = m_cursor_drag_image;
		}
		else if (m_drag_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_drag_animtime) % m_cursor_drag_animation->getDuration();
			img = m_cursor_drag_animation->getFrameByTimestamp(animtime);
		}

		if (img != 0) {
			Rect area(m_mx + m_drag_offset_x + img->getXShift(), m_my + m_drag_offset_y + img->getYShift(), img->getWidth(), img->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}

		ImagePtr img2;
		// render possible cursor image
		if (m_cursor_type == CURSOR_IMAGE) {
			img2 = m_cursor_image;
		}
		else if (m_cursor_type == CURSOR_ANIMATION) {
			int32_t animtime = (m_timemanager->getTime() - m_animtime) % m_cursor_animation->getDuration();
			img2 = m_cursor_animation->getFrameByTimestamp(animtime);
		}

		if (img2 != 0) {
			Rect area(m_mx + img2->getXShift(), m_my + img2->getYShift(), img2->getWidth(), img2->getHeight());
			m_renderbackend->pushClipArea(area, false);
			img2->render(area);
			m_renderbackend->renderVertexArrays();
			m_renderbackend->popClipArea();
		}
	}

	uint32_t Cursor::getNativeId(uint32_t cursor_id) {
		switch (cursor_id) {
			case NC_ARROW:
				return SDL_SYSTEM_CURSOR_ARROW;
			case NC_IBEAM:
				return SDL_SYSTEM_CURSOR_IBEAM;
			case NC_WAIT:
				return SDL_SYSTEM_CURSOR_WAIT;
			case NC_CROSS:
				return SDL_SYSTEM_CURSOR_CROSSHAIR;
			case NC_WAITARROW:
				return SDL_SYSTEM_CURSOR_WAITARROW;
			case NC_RESIZENWSE:
				return SDL_SYSTEM_CURSOR_SIZENWSE;
			case NC_RESIZENESW:
				return SDL_SYSTEM_CURSOR_SIZENESW;
			case NC_RESIZEWE:
				return SDL_SYSTEM_CURSOR_SIZEWE;
			case NC_RESIZENS:
				return SDL_SYSTEM_CURSOR_SIZENS;
			case NC_RESIZEALL:
				return SDL_SYSTEM_CURSOR_SIZEALL;
			case NC_NO:
				return SDL_SYSTEM_CURSOR_NO;
			case NC_HAND:
				return SDL_SYSTEM_CURSOR_HAND;
		}
		return cursor_id;
	}

	void Cursor::setNativeCursor(uint32_t cursor_id) {
		cursor_id = getNativeId(cursor_id);
		SDL_Cursor* cursor = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(cursor_id));
		if (!cursor) {
			FL_WARN(_log, "Cursor: No cursor matching cursor_id was found.");
			return;
		}
		m_native_cursor = cursor;
		SDL_SetCursor(cursor);
	}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: PageMasterPropHdl.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: th $ $Date: 2001-05-11 10:52:52 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_PAGEMASTERPROPHDL_HXX_
#include "PageMasterPropHdl.hxx"
#endif

#ifndef _XMLOFF_XMLKYWD_HXX
#include "xmlkywd.hxx"
#endif
#ifndef _XMLOFF_XMLUCONV_HXX
#include "xmluconv.hxx"
#endif
#ifndef _XMLOFF_XMLNUMI_HXX
#include "xmlnumi.hxx"
#endif
#ifndef _XMLOFF_XMLNUME_HXX
#include "xmlnume.hxx"
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_STYLE_PAGESTYLELAYOUT_HPP_
#include <com/sun/star/style/PageStyleLayout.hpp>
#endif

#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::style;
using namespace ::comphelper;

//______________________________________________________________________________

#define DEFAULT_PAPERTRAY   (sal_Int32(-1))

//______________________________________________________________________________
// property handler for style:page-usage (style::PageStyleLayout)

XMLPMPropHdl_PageStyleLayout::~XMLPMPropHdl_PageStyleLayout()
{
}

sal_Bool XMLPMPropHdl_PageStyleLayout::equals( const Any& rAny1, const Any& rAny2 ) const
{
    style::PageStyleLayout eLayout1, eLayout2;
    return ((rAny1 >>= eLayout1) && (rAny2 >>= eLayout2)) ? (eLayout1 == eLayout2) : sal_False;
}

sal_Bool XMLPMPropHdl_PageStyleLayout::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_True;

    if( rStrImpValue.compareToAscii( sXML_all ) == 0 )
        rValue <<= PageStyleLayout_ALL;
    else if( rStrImpValue.compareToAscii( sXML_left ) == 0 )
        rValue <<= PageStyleLayout_LEFT;
    else if( rStrImpValue.compareToAscii( sXML_right ) == 0 )
        rValue <<= PageStyleLayout_RIGHT;
    else if( rStrImpValue.compareToAscii( sXML_mirrored ) == 0 )
        rValue <<= PageStyleLayout_MIRRORED;
    else
        bRet = sal_False;

    return bRet;
}

sal_Bool XMLPMPropHdl_PageStyleLayout::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool        bRet = sal_False;
    PageStyleLayout eLayout;

    if( rValue >>= eLayout )
    {
        bRet = sal_True;
        switch( eLayout )
        {
            case PageStyleLayout_ALL:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_all ) );
            break;
            case PageStyleLayout_LEFT:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_left ) );
            break;
            case PageStyleLayout_RIGHT:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_right ) );
            break;
            case PageStyleLayout_MIRRORED:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_mirrored ) );
            break;
            default:
                bRet = sal_False;
        }
    }

    return bRet;
}

//______________________________________________________________________________
// property handler for style:num-format (style::NumberingType)

XMLPMPropHdl_NumFormat::~XMLPMPropHdl_NumFormat()
{
}

sal_Bool XMLPMPropHdl_NumFormat::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Int16 nSync;
    sal_Int16 nNumType = NumberingType::NUMBER_NONE;
    rUnitConverter.convertNumFormat( nNumType, rStrImpValue, OUString(),
                                     sal_True );

    if( !(rValue >>= nSync) )
        nSync = NumberingType::NUMBER_NONE;

    // if num-letter-sync appears before num-format, the function
    // XMLPMPropHdl_NumLetterSync::importXML() sets the value
    // NumberingType::CHARS_LOWER_LETTER_N
    if( nSync == NumberingType::CHARS_LOWER_LETTER_N )
    {
        switch( nNumType )
        {
            case NumberingType::CHARS_LOWER_LETTER:
                nNumType = NumberingType::CHARS_LOWER_LETTER_N;
            break;
            case NumberingType::CHARS_UPPER_LETTER:
                nNumType = NumberingType::CHARS_UPPER_LETTER_N;
            break;
        }
    }
    rValue <<= nNumType;

    return sal_True;
}

sal_Bool XMLPMPropHdl_NumFormat::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int16   nNumType;

    if( rValue >>= nNumType )
    {
        OUStringBuffer aBuffer( 10 );
        rUnitConverter.convertNumFormat( aBuffer, nNumType );
        rStrExpValue = aBuffer.makeStringAndClear();
        bRet = rStrExpValue.getLength() > 0;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:num-letter-sync (style::NumberingType)

XMLPMPropHdl_NumLetterSync::~XMLPMPropHdl_NumLetterSync()
{
}

sal_Bool XMLPMPropHdl_NumLetterSync::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Int16 nNumType;
    sal_Int16 nSync = NumberingType::NUMBER_NONE;
    rUnitConverter.convertNumFormat( nSync, rStrImpValue,
                OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_a ) ),
                sal_True );

    if( !(rValue >>= nNumType) )
        nNumType = NumberingType::NUMBER_NONE;

    if( nSync == NumberingType::CHARS_LOWER_LETTER_N )
    {
        switch( nNumType )
        {
            case NumberingType::CHARS_LOWER_LETTER:
                nNumType = NumberingType::CHARS_LOWER_LETTER_N;
            break;
            case NumberingType::CHARS_UPPER_LETTER:
                nNumType = NumberingType::CHARS_UPPER_LETTER_N;
            break;
        }
    }
    rValue <<= nNumType;

    return sal_True;
}

sal_Bool XMLPMPropHdl_NumLetterSync::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int16   nNumType;

    if( rValue >>= nNumType )
    {
        OUStringBuffer aBuffer( 5 );
        rUnitConverter.convertNumLetterSync( aBuffer, nNumType );
        rStrExpValue = aBuffer.makeStringAndClear();
        bRet = rStrExpValue.getLength() > 0;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:paper-tray-number

XMLPMPropHdl_PaperTrayNumber::~XMLPMPropHdl_PaperTrayNumber()
{
}

sal_Bool XMLPMPropHdl_PaperTrayNumber::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if( rStrImpValue.compareToAscii( sXML_default ) == 0 )
    {
        rValue <<= DEFAULT_PAPERTRAY;
        bRet = sal_True;
    }
    else
    {
        sal_Int32 nPaperTray;
        if( SvXMLUnitConverter::convertNumber( nPaperTray, rStrImpValue, 0 ) )
        {
            rValue <<= nPaperTray;
            bRet = sal_True;
        }
    }

    return bRet;
}

sal_Bool XMLPMPropHdl_PaperTrayNumber::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int32   nPaperTray;

    if( rValue >>= nPaperTray )
    {
        if( nPaperTray == DEFAULT_PAPERTRAY )
            rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_default ) );
        else
        {
            OUStringBuffer aBuffer;
            SvXMLUnitConverter::convertNumber( aBuffer, nPaperTray );
            rStrExpValue = aBuffer.makeStringAndClear();
        }
        bRet = sal_True;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:print

XMLPMPropHdl_Print::XMLPMPropHdl_Print( const sal_Char* sValue ) :
    sAttrValue( OUString::createFromAscii( sValue ) )
{
}

XMLPMPropHdl_Print::~XMLPMPropHdl_Print()
{
}

sal_Bool XMLPMPropHdl_Print::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Unicode cToken  = ' ';
    sal_Int32   nTokenIndex = 0;
    sal_Bool    bFound  = sal_False;

    do
    {
        bFound = (sAttrValue == rStrImpValue.getToken( 0, cToken, nTokenIndex ));
    }
    while ( (nTokenIndex >= 0) && !bFound );

    setBOOL( rValue, bFound );
    return sal_True;
}

sal_Bool XMLPMPropHdl_Print::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    if( getBOOL( rValue ) )
    {
        if( rStrExpValue.getLength() )
            rStrExpValue += OUString( RTL_CONSTASCII_USTRINGPARAM( " " ) );
        rStrExpValue += sAttrValue;
    }

    return sal_True;
}

//______________________________________________________________________________
// property handler for style:table-centering

XMLPMPropHdl_CenterHorizontal::~XMLPMPropHdl_CenterHorizontal()
{
}

sal_Bool XMLPMPropHdl_CenterHorizontal::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if (rStrImpValue.getLength())
        if ((rStrImpValue.compareToAscii(sXML_both) == 0) ||
            (rStrImpValue.compareToAscii(sXML_horizontal) == 0))
        {
            rValue = ::cppu::bool2any(sal_True);
            bRet = sal_True;
        }

    return bRet;
}

sal_Bool XMLPMPropHdl_CenterHorizontal::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;

    if ( ::cppu::any2bool( rValue ) )
    {
        bRet = sal_True;
        if (rStrExpValue.getLength())
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_both));
        else
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_horizontal));
    }

    return bRet;
}

XMLPMPropHdl_CenterVertical::~XMLPMPropHdl_CenterVertical()
{
}

sal_Bool XMLPMPropHdl_CenterVertical::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if (rStrImpValue.getLength())
        if ((rStrImpValue.compareToAscii(sXML_both) == 0) ||
            (rStrImpValue.compareToAscii(sXML_vertical) == 0))
        {
            rValue = ::cppu::bool2any(sal_True);
            bRet = sal_True;
        }

    return bRet;
}

sal_Bool XMLPMPropHdl_CenterVertical::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;

    if ( ::cppu::any2bool( rValue ) )
    {
        bRet = sal_True;
        if (rStrExpValue.getLength())
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_both));
        else
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_vertical));
    }

    return bRet;
}

<commit_msg>#88948#: page number setting 'none'<commit_after>/*************************************************************************
 *
 *  $RCSfile: PageMasterPropHdl.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: mib $ $Date: 2001-06-29 11:18:45 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_PAGEMASTERPROPHDL_HXX_
#include "PageMasterPropHdl.hxx"
#endif

#ifndef _XMLOFF_XMLKYWD_HXX
#include "xmlkywd.hxx"
#endif
#ifndef _XMLOFF_XMLUCONV_HXX
#include "xmluconv.hxx"
#endif
#ifndef _XMLOFF_XMLNUMI_HXX
#include "xmlnumi.hxx"
#endif
#ifndef _XMLOFF_XMLNUME_HXX
#include "xmlnume.hxx"
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_STYLE_PAGESTYLELAYOUT_HPP_
#include <com/sun/star/style/PageStyleLayout.hpp>
#endif

#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::style;
using namespace ::comphelper;

//______________________________________________________________________________

#define DEFAULT_PAPERTRAY   (sal_Int32(-1))

//______________________________________________________________________________
// property handler for style:page-usage (style::PageStyleLayout)

XMLPMPropHdl_PageStyleLayout::~XMLPMPropHdl_PageStyleLayout()
{
}

sal_Bool XMLPMPropHdl_PageStyleLayout::equals( const Any& rAny1, const Any& rAny2 ) const
{
    style::PageStyleLayout eLayout1, eLayout2;
    return ((rAny1 >>= eLayout1) && (rAny2 >>= eLayout2)) ? (eLayout1 == eLayout2) : sal_False;
}

sal_Bool XMLPMPropHdl_PageStyleLayout::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_True;

    if( rStrImpValue.compareToAscii( sXML_all ) == 0 )
        rValue <<= PageStyleLayout_ALL;
    else if( rStrImpValue.compareToAscii( sXML_left ) == 0 )
        rValue <<= PageStyleLayout_LEFT;
    else if( rStrImpValue.compareToAscii( sXML_right ) == 0 )
        rValue <<= PageStyleLayout_RIGHT;
    else if( rStrImpValue.compareToAscii( sXML_mirrored ) == 0 )
        rValue <<= PageStyleLayout_MIRRORED;
    else
        bRet = sal_False;

    return bRet;
}

sal_Bool XMLPMPropHdl_PageStyleLayout::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool        bRet = sal_False;
    PageStyleLayout eLayout;

    if( rValue >>= eLayout )
    {
        bRet = sal_True;
        switch( eLayout )
        {
            case PageStyleLayout_ALL:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_all ) );
            break;
            case PageStyleLayout_LEFT:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_left ) );
            break;
            case PageStyleLayout_RIGHT:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_right ) );
            break;
            case PageStyleLayout_MIRRORED:
                rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_mirrored ) );
            break;
            default:
                bRet = sal_False;
        }
    }

    return bRet;
}

//______________________________________________________________________________
// property handler for style:num-format (style::NumberingType)

XMLPMPropHdl_NumFormat::~XMLPMPropHdl_NumFormat()
{
}

sal_Bool XMLPMPropHdl_NumFormat::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Int16 nSync;
    sal_Int16 nNumType = NumberingType::NUMBER_NONE;
    rUnitConverter.convertNumFormat( nNumType, rStrImpValue, OUString(),
                                     sal_True );

    if( !(rValue >>= nSync) )
        nSync = NumberingType::NUMBER_NONE;

    // if num-letter-sync appears before num-format, the function
    // XMLPMPropHdl_NumLetterSync::importXML() sets the value
    // NumberingType::CHARS_LOWER_LETTER_N
    if( nSync == NumberingType::CHARS_LOWER_LETTER_N )
    {
        switch( nNumType )
        {
            case NumberingType::CHARS_LOWER_LETTER:
                nNumType = NumberingType::CHARS_LOWER_LETTER_N;
            break;
            case NumberingType::CHARS_UPPER_LETTER:
                nNumType = NumberingType::CHARS_UPPER_LETTER_N;
            break;
        }
    }
    rValue <<= nNumType;

    return sal_True;
}

sal_Bool XMLPMPropHdl_NumFormat::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int16   nNumType;

    if( rValue >>= nNumType )
    {
        OUStringBuffer aBuffer( 10 );
        rUnitConverter.convertNumFormat( aBuffer, nNumType );
        rStrExpValue = aBuffer.makeStringAndClear();
        bRet = sal_True;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:num-letter-sync (style::NumberingType)

XMLPMPropHdl_NumLetterSync::~XMLPMPropHdl_NumLetterSync()
{
}

sal_Bool XMLPMPropHdl_NumLetterSync::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Int16 nNumType;
    sal_Int16 nSync = NumberingType::NUMBER_NONE;
    rUnitConverter.convertNumFormat( nSync, rStrImpValue,
                OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_a ) ),
                sal_True );

    if( !(rValue >>= nNumType) )
        nNumType = NumberingType::NUMBER_NONE;

    if( nSync == NumberingType::CHARS_LOWER_LETTER_N )
    {
        switch( nNumType )
        {
            case NumberingType::CHARS_LOWER_LETTER:
                nNumType = NumberingType::CHARS_LOWER_LETTER_N;
            break;
            case NumberingType::CHARS_UPPER_LETTER:
                nNumType = NumberingType::CHARS_UPPER_LETTER_N;
            break;
        }
    }
    rValue <<= nNumType;

    return sal_True;
}

sal_Bool XMLPMPropHdl_NumLetterSync::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int16   nNumType;

    if( rValue >>= nNumType )
    {
        OUStringBuffer aBuffer( 5 );
        rUnitConverter.convertNumLetterSync( aBuffer, nNumType );
        rStrExpValue = aBuffer.makeStringAndClear();
        bRet = rStrExpValue.getLength() > 0;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:paper-tray-number

XMLPMPropHdl_PaperTrayNumber::~XMLPMPropHdl_PaperTrayNumber()
{
}

sal_Bool XMLPMPropHdl_PaperTrayNumber::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if( rStrImpValue.compareToAscii( sXML_default ) == 0 )
    {
        rValue <<= DEFAULT_PAPERTRAY;
        bRet = sal_True;
    }
    else
    {
        sal_Int32 nPaperTray;
        if( SvXMLUnitConverter::convertNumber( nPaperTray, rStrImpValue, 0 ) )
        {
            rValue <<= nPaperTray;
            bRet = sal_True;
        }
    }

    return bRet;
}

sal_Bool XMLPMPropHdl_PaperTrayNumber::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;
    sal_Int32   nPaperTray;

    if( rValue >>= nPaperTray )
    {
        if( nPaperTray == DEFAULT_PAPERTRAY )
            rStrExpValue = OUString( RTL_CONSTASCII_USTRINGPARAM( sXML_default ) );
        else
        {
            OUStringBuffer aBuffer;
            SvXMLUnitConverter::convertNumber( aBuffer, nPaperTray );
            rStrExpValue = aBuffer.makeStringAndClear();
        }
        bRet = sal_True;
    }
    return bRet;
}

//______________________________________________________________________________
// property handler for style:print

XMLPMPropHdl_Print::XMLPMPropHdl_Print( const sal_Char* sValue ) :
    sAttrValue( OUString::createFromAscii( sValue ) )
{
}

XMLPMPropHdl_Print::~XMLPMPropHdl_Print()
{
}

sal_Bool XMLPMPropHdl_Print::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Unicode cToken  = ' ';
    sal_Int32   nTokenIndex = 0;
    sal_Bool    bFound  = sal_False;

    do
    {
        bFound = (sAttrValue == rStrImpValue.getToken( 0, cToken, nTokenIndex ));
    }
    while ( (nTokenIndex >= 0) && !bFound );

    setBOOL( rValue, bFound );
    return sal_True;
}

sal_Bool XMLPMPropHdl_Print::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    if( getBOOL( rValue ) )
    {
        if( rStrExpValue.getLength() )
            rStrExpValue += OUString( RTL_CONSTASCII_USTRINGPARAM( " " ) );
        rStrExpValue += sAttrValue;
    }

    return sal_True;
}

//______________________________________________________________________________
// property handler for style:table-centering

XMLPMPropHdl_CenterHorizontal::~XMLPMPropHdl_CenterHorizontal()
{
}

sal_Bool XMLPMPropHdl_CenterHorizontal::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if (rStrImpValue.getLength())
        if ((rStrImpValue.compareToAscii(sXML_both) == 0) ||
            (rStrImpValue.compareToAscii(sXML_horizontal) == 0))
        {
            rValue = ::cppu::bool2any(sal_True);
            bRet = sal_True;
        }

    return bRet;
}

sal_Bool XMLPMPropHdl_CenterHorizontal::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;

    if ( ::cppu::any2bool( rValue ) )
    {
        bRet = sal_True;
        if (rStrExpValue.getLength())
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_both));
        else
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_horizontal));
    }

    return bRet;
}

XMLPMPropHdl_CenterVertical::~XMLPMPropHdl_CenterVertical()
{
}

sal_Bool XMLPMPropHdl_CenterVertical::importXML(
        const OUString& rStrImpValue,
        Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;

    if (rStrImpValue.getLength())
        if ((rStrImpValue.compareToAscii(sXML_both) == 0) ||
            (rStrImpValue.compareToAscii(sXML_vertical) == 0))
        {
            rValue = ::cppu::bool2any(sal_True);
            bRet = sal_True;
        }

    return bRet;
}

sal_Bool XMLPMPropHdl_CenterVertical::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool    bRet = sal_False;

    if ( ::cppu::any2bool( rValue ) )
    {
        bRet = sal_True;
        if (rStrExpValue.getLength())
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_both));
        else
            rStrExpValue = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(sXML_vertical));
    }

    return bRet;
}

<|endoftext|>


<commit_before>#include <QCoreApplication>
#include <QtDebug>

#include <iostream>
#include <fstream>
//#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <cerrno>
#include <cmath>
#include <thread>
#include <mutex>

#define OUTPUT_FILE "./trials.csv"
#define NUMBER_THREADS 7
#define USE_MULTIPLE_THREADS
// create a mutex that is used to protect the writing of the data to
// the file.
std::mutex writeToFile;

#ifndef M_PI
#define M_PI 3.14159265359
#endif

#define SHOW_PROGRESS
//#define SHOW_INTERMEDIATE
#define BASE_DT 0.0001

double drand48()
{
    return((double)(rand())/((double)RAND_MAX));
}

void normalDistRand(double stdDev,double* randomNumbers)
    {
        /* Generate a random number in polar coordinates */
        double radius = sqrt(-2.0*log(drand48()));
        double angle = 2.0*M_PI*drand48();
        /* transform the number back into cartesian coordinates */
        randomNumbers[0] = stdDev*radius*sin(angle);
        randomNumbers[1] = stdDev*radius*cos(angle);
    }

void printToCSVFile(double dt, double beta, double g,double tau,
                    double q, double theta, double h,double s,
                    double *x,std::ofstream *fp)
{

    std::lock_guard<std::mutex> guard(writeToFile);  // Make sure that
                                                       // this routine
                                                       // can only
                                                       // access the file once
                                                       // at any one time.

    *fp << dt << ","
        << beta << ","
        << g << ","
        << tau << ","
        << q+1 << ","
        << theta << ","
        << h << ","
        << s << ","
        << 1-h-s << ","
        << x[0] << ","
        << x[1] << ","
        << 1-x[0]-x[1] << ","
        << x[2] << ","
        << x[3] << ","
        << 1-x[2]-x[3]
        << std::endl;

    (*fp).flush();
}

void linear(long steps,
              double a,double gamma,double r,double d,double g,
              double *x,double *y,double *z, double dt,
              int n,
              double beta,double tau,
              std::ofstream *fp,
              int q,
              double h,double s,double *v,double *w, double theta)
    {

        long m=n-1;
        long p=0;
        double B[2];
        int calcRandom=0;

        // Step through every time step.
        for (long k=0;k<steps;k++)
        {

            // Calculate a new set of random numbers if necessary.
            if(calcRandom==0)
                normalDistRand(sqrt(dt),B); //noise in most recent time step

            //x[0]=y[m]+(y[m]*(gamma-gamma*y[m]+(a-gamma)*z[m])-(g*y[p]/(1-z[p])))*dt
            //x[0]=x[0]+beta*y[m]*(1-y[m])+0.5*beta*y[m]*(1-y[m])*beta*(1-2*y[m])*(B[calcRandom]*B[calcRandom]-dt);

            //Computes the deterministic component for Macroalgae
            x[0] = y[m]+(y[m]*(gamma-gamma*y[m]+(a-gamma)*z[m])-(g*y[p]/(1-z[p])))*dt;

            //Adds in the noise
            //x[0]=x[0]+beta*y[m]*B[calcRandom]+0.5*beta*y[m]*beta*(B[calcRandom]*B[calcRandom]-dt);
            x[0] += beta*y[m]*B[calcRandom]+0.5*beta*beta*y[m]*(B[calcRandom]*B[calcRandom]-dt);

            //Computes the deterministic component for Coral
            x[1] = z[m]+(z[m]*(r-d-(a+r)*y[m]-r*z[m]))*dt;

            x[2] =  v[m]+(v[m]*(gamma-gamma*v[m]+(a-gamma)*w[m])-(g*v[p]/(1-w[p])))*dt;
            x[2] += beta*v[m]*(1-v[m])*B[calcRandom]+0.5*beta*(1-2*v[m])*beta*v[m]*(1-v[m])*(B[calcRandom]*B[calcRandom]-dt);
            x[3] =  w[m]+(w[m]*(r-d-(a+r)*v[m]-r*w[m]))*dt;

            /****************************************************************
                Account for extinction and overgrowing!!
            ****************************************************************/
            for(int i=0;i<4;++i)
                {
                    if(x[i]<0.0)
                        x[i] = 0.0;
                    else if (x[i]>1.0)
                        x[i] = 1.0;
                }

            //Updates delay and cell index
            m=(m+1)%n;
            p=(p+1)%n;
            y[m]=x[0];
            z[m]=x[1];
            v[m]=x[2];
            w[m]=x[3];
            calcRandom = (calcRandom+1)%2; // update which random number to use.

        }

        //printf("%f\t%f\t%f\t%f\t%f\n",dt,beta,tau,x[0],x[1]);
        printToCSVFile(dt,beta,g,tau,q,theta,h,s,x,fp);

 #ifdef SHOW_INTERMEDIATE
        qDebug() << dt << ","
            << beta << ","
            << g << ","
            << tau << ","
            << q+1 << ","
            << h << ","
            << s << ","
            << 1-h-s << ","
            << x[0] << ","
            << x[1] << ","
            << 1-x[0]-x[1] << ","
            << x[2] << ","
            << x[3] << ","
            << 1-x[2]-x[3];
        qDebug() << errno << EDOM << ERANGE;
#endif

    }

/* ****************************************************************
     main

     The main function. Called at the start of the program.
**************************************************************** */
int main(int argc, char *argv[])
{
    QCoreApplication b(argc, argv);

        long steps;    // The number of steps to take in a single simulation.
        double *v,*w,*x,*y,*z;  // The variables used for the state of the system.

        /*
            Define the constants.

            These are the parameters that are used in the operator for the
            differential equations.
         */
        double a    	 = 0.1;
        double g    	 = 0.3;
        double gamma	 = 0.8;
        double r    	 = 1.0;
        double d    	 = 0.44;
    //	double tau		 = 0.5;
        double beta //	 = .5;
        double chi		 = r*gamma/(r+a)-gamma+a;					//Intermediate Step
        double xi		 = -(d*gamma/(r+a)+a);						//Intermediate Step
        double cbar		 = (-xi-sqrt(xi*xi-4*chi*g))/(2*chi);		//Intermediate Step
        double coralSaddle		 = 1-cbar;						    //Saddle point value for coral
        double macroSaddle		 = (r-r*coralSaddle-d)/(r+a);		//Saddle point value for macroalgae
        double gZero	 = ((d*a*r+d*d)*(gamma-a))/(r*r);
        double gOne		 = (gamma*(a+d))/(a+r);
        double omega	 = sqrt((r*r*(g*g-gZero*gZero))/(d*d));
        double tauZero	 = (1/omega)*acos(gZero/g);

        double dt        = .0001;          // Set the initial time step
        long   numberDT;    // The current iteration for the number assocated with the value of dt.
        double final;       // The final time for each simulation.
        long   trials;      // The number of simulations to make.

<<<<<<< HEAD
        final=50;  // Set the final time.
        trials=400; // Set the number of trials to perform.
=======
        final=50.0;  // Set the final time.
        trials=50;   // Set the number of trials to perform.
>>>>>>> afa3c18ff2f48dc4ee88e7e8158f5b78dae8cb48

        // Set the time delay, tau
        double tau = 0.5;

        // set up the variables for using different approximations on different threads.
        std::thread simulation[NUMBER_THREADS];
        int numberThreads = 0;

        // Sets the seed for the random numbers
        srand(time(NULL));

        // Create a CSV File
        std::ofstream fp;
                //String fileName = "trials-g" + std::toString(g) + "-tau" + std::toString(tau);
        fp.open(OUTPUT_FILE,std::ios::out | std::ios::trunc);

        fp << "dt,beta,g,tau,trial,theta,initMacro,initCoral,initTurf,macroalgae,coral,turf,lgMacro,lgCoral,lgTurf" << std::endl;

/*		for (g=0.1;g<=0.8;g=g+0.02)
            {
                //Redefine initial conditions and critical points for varying g
                cbar		 = (-xi-sqrt(xi*xi-4*chi*g))/(2*chi);
                coralSaddle		 = 1-cbar;
                macroSaddle		 = (r-r*coralSaddle-d)/(r+a);
                omega	 = sqrt((r*r*(g*g-gZero*gZero))/(d*d));
                tauZero	 = (1/omega)*acos(gZero/g);
                if (coralSaddle>0 && coralSaddle<1 && macroSaddle>0 && macroSaddle<1 && tauZero>0)
            for (double aleph=0;aleph<=5;aleph=aleph+1)
            {

                tau=.3*(1+aleph)*tauZero;
                dt=0.0001;
*/

           // Determine the number of time steps required to move back to the delay in time.
           // The number of cells needed for the delay (changes with dt)
            int n;
            n=(int)(tau/BASE_DT+0.5);

            // Allocate the space for the states of the system
            x=(double *) calloc(4,sizeof(double));
            y=(double *) calloc(n,sizeof(double));		//macroalgae for multiplicative noise
            z=(double *) calloc(n,sizeof(double));		//coral for multiplicative noise
            v=(double *) calloc(n,sizeof(double));		//macroalgae for logistic noise
            w=(double *) calloc(n,sizeof(double));		//coral for logistic noise
<<<<<<< HEAD
            //for(numberDT=1;numberDT<5;++numberDT)
                    dt = BASE_DT; //(double)numberDT;
                    //printf("%f\t%f\n",dt,fmod(tau,dt));
=======

            // Make different approximations for different values for the time steps.
            for(beta=.1;beta<=.45; beta += .05)
                {
                    //dt = BASE_DT*(double)numberDT;
>>>>>>> afa3c18ff2f48dc4ee88e7e8158f5b78dae8cb48
#ifdef SHOW_PROGRESS
                    std::cout << "dt = " << dt << std::endl;
#endif
                    if ((int)(10000.0*tau+.5)%(int)(dt*10000.0+.5)==0)
                    {
                        //index = tau/dt;
                        n=(int)(tau/dt+.5);
                        //printf("%i\n",n);
                        steps=(long)(final/dt);
<<<<<<< HEAD
                        for (double theta=0;theta<=M_PI/2;theta+=(M_PI*0.5)*0.025)
=======

                        // Make an approximation for different initial conditions.
                        // Make an arc through 0 to pi/2 radians from the origin.
                        for (double theta=0;theta<=M_PI/2;theta+=(M_PI*0.5)*0.05)
>>>>>>> afa3c18ff2f48dc4ee88e7e8158f5b78dae8cb48
                        {
                            for (int k=0;k<trials;k++)
                            {
                                y[0]=0.06*cos(theta); //initial Macroalgae level
                                z[0]=0.06*sin(theta); //initial Coral level
                                v[0]=0.06*cos(theta);
                                w[0]=0.06*sin(theta);
                                for (int l=1;l<n;l++) //fills in the past times for y, z, v, and w
                                {
                                    y[l]=y[0];
                                    z[l]=z[0];
                                    v[l]=v[0];
                                    w[l]=w[0];
                                }
                                //fprintf(fp,"%f,%f,%f,%f,%f,%f\n",y[0],z[0],1-y[0]-z[0],v[0],w[0],1-v[0]-w[0]);
#ifdef USE_MULTIPLE_THREADS

                                // Make a simulation for each of the available threads.
                                // First check to see how many threads are running.
                                if(numberThreads >= NUMBER_THREADS)
                                {
                                    // There are too many threads. Wait for each run to end.
                                    while(numberThreads>0)
                                    {
#ifdef THREAD_DEBUG
                                        std::cout << "Waiting on thread "
                                                  << simulation[numberThreads-1].get_id()
                                                  << std::endl;
#endif
                                        simulation[--numberThreads].join();
                                    }
                                }

                                // Make a run in a separate thread.
                                simulation[numberThreads++] = std::thread(linear,
                                                                          steps,a,gamma,r,d,g,x,y,z,dt,n,beta,tau,&fp,k,y[0],z[0],v,w,theta);

#else

                                // Ignore the different threads. Just make one approximation in this one thread.
                                linear(steps,a,gamma,r,d,g,x,y,z,dt,n,beta,tau,&fp,k,y[0],z[0],v,w,theta);

#endif

#ifdef SHOW_PROGRESS
                                if(k%20 == 0)
                                    std::cout << "  Simulation number " << k << std::endl;
#endif

                            }
                        }
            }

            // Free up the allocated memory.
            free(x);
            free(y);
            free(z);
            free(v);
            free(w);
            //}
            //}

        fp.close();

#ifdef SHOW_PROGRESS
            std::cout << "all done" << std::endl;
#endif

        return b.exec();
}
<commit_msg>I think I fixed the merging problems(?)<commit_after>#include <QCoreApplication>
#include <QtDebug>

#include <iostream>
#include <fstream>
//#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <cerrno>
#include <cmath>
#include <thread>
#include <mutex>

#define OUTPUT_FILE "./trials.csv"
#define NUMBER_THREADS 7
#define USE_MULTIPLE_THREADS
// create a mutex that is used to protect the writing of the data to
// the file.
std::mutex writeToFile;

#ifndef M_PI
#define M_PI 3.14159265359
#endif

#define SHOW_PROGRESS
//#define SHOW_INTERMEDIATE
#define BASE_DT 0.0001

double drand48()
{
    return((double)(rand())/((double)RAND_MAX));
}

void normalDistRand(double stdDev,double* randomNumbers)
    {
        /* Generate a random number in polar coordinates */
        double radius = sqrt(-2.0*log(drand48()));
        double angle = 2.0*M_PI*drand48();
        /* transform the number back into cartesian coordinates */
        randomNumbers[0] = stdDev*radius*sin(angle);
        randomNumbers[1] = stdDev*radius*cos(angle);
    }

void printToCSVFile(double dt, double beta, double g,double tau,
                    double q, double theta, double h,double s,
                    double *x,std::ofstream *fp)
{

    std::lock_guard<std::mutex> guard(writeToFile);  // Make sure that
                                                       // this routine
                                                       // can only
                                                       // access the file once
                                                       // at any one time.

    *fp << dt << ","
        << beta << ","
        << g << ","
        << tau << ","
        << q+1 << ","
        << theta << ","
        << h << ","
        << s << ","
        << 1-h-s << ","
        << x[0] << ","
        << x[1] << ","
        << 1-x[0]-x[1] << ","
        << x[2] << ","
        << x[3] << ","
        << 1-x[2]-x[3]
        << std::endl;

    (*fp).flush();
}

void linear(long steps,
              double a,double gamma,double r,double d,double g,
              double *x,double *y,double *z, double dt,
              int n,
              double beta,double tau,
              std::ofstream *fp,
              int q,
              double h,double s,double *v,double *w, double theta)
    {

        long m=n-1;
        long p=0;
        double B[2];
        int calcRandom=0;

        // Step through every time step.
        for (long k=0;k<steps;k++)
        {

            // Calculate a new set of random numbers if necessary.
            if(calcRandom==0)
                normalDistRand(sqrt(dt),B); //noise in most recent time step

            //x[0]=y[m]+(y[m]*(gamma-gamma*y[m]+(a-gamma)*z[m])-(g*y[p]/(1-z[p])))*dt
            //x[0]=x[0]+beta*y[m]*(1-y[m])+0.5*beta*y[m]*(1-y[m])*beta*(1-2*y[m])*(B[calcRandom]*B[calcRandom]-dt);

            //Computes the deterministic component for Macroalgae
            x[0] = y[m]+(y[m]*(gamma-gamma*y[m]+(a-gamma)*z[m])-(g*y[p]/(1-z[p])))*dt;

            //Adds in the noise
            //x[0]=x[0]+beta*y[m]*B[calcRandom]+0.5*beta*y[m]*beta*(B[calcRandom]*B[calcRandom]-dt);
            x[0] += beta*y[m]*B[calcRandom]+0.5*beta*beta*y[m]*(B[calcRandom]*B[calcRandom]-dt);

            //Computes the deterministic component for Coral
            x[1] = z[m]+(z[m]*(r-d-(a+r)*y[m]-r*z[m]))*dt;

            x[2] =  v[m]+(v[m]*(gamma-gamma*v[m]+(a-gamma)*w[m])-(g*v[p]/(1-w[p])))*dt;
            x[2] += beta*v[m]*(1-v[m])*B[calcRandom]+0.5*beta*(1-2*v[m])*beta*v[m]*(1-v[m])*(B[calcRandom]*B[calcRandom]-dt);
            x[3] =  w[m]+(w[m]*(r-d-(a+r)*v[m]-r*w[m]))*dt;

            /****************************************************************
                Account for extinction and overgrowing!!
            ****************************************************************/
            for(int i=0;i<4;++i)
                {
                    if(x[i]<0.0)
                        x[i] = 0.0;
                    else if (x[i]>1.0)
                        x[i] = 1.0;
                }

            //Updates delay and cell index
            m=(m+1)%n;
            p=(p+1)%n;
            y[m]=x[0];
            z[m]=x[1];
            v[m]=x[2];
            w[m]=x[3];
            calcRandom = (calcRandom+1)%2; // update which random number to use.

        }

        //printf("%f\t%f\t%f\t%f\t%f\n",dt,beta,tau,x[0],x[1]);
        printToCSVFile(dt,beta,g,tau,q,theta,h,s,x,fp);

 #ifdef SHOW_INTERMEDIATE
        qDebug() << dt << ","
            << beta << ","
            << g << ","
            << tau << ","
            << q+1 << ","
            << h << ","
            << s << ","
            << 1-h-s << ","
            << x[0] << ","
            << x[1] << ","
            << 1-x[0]-x[1] << ","
            << x[2] << ","
            << x[3] << ","
            << 1-x[2]-x[3];
        qDebug() << errno << EDOM << ERANGE;
#endif

    }

/* ****************************************************************
     main

     The main function. Called at the start of the program.
**************************************************************** */
int main(int argc, char *argv[])
{
    QCoreApplication b(argc, argv);

        long steps;    // The number of steps to take in a single simulation.
        double *v,*w,*x,*y,*z;  // The variables used for the state of the system.

        /*
            Define the constants.

            These are the parameters that are used in the operator for the
            differential equations.
         */
        double a    	 = 0.1;
        double g    	 = 0.3;
        double gamma	 = 0.8;
        double r    	 = 1.0;
        double d    	 = 0.44;
    //	double tau		 = 0.5;
        double beta //	 = .5;
        double chi		 = r*gamma/(r+a)-gamma+a;					//Intermediate Step
        double xi		 = -(d*gamma/(r+a)+a);						//Intermediate Step
        double cbar		 = (-xi-sqrt(xi*xi-4*chi*g))/(2*chi);		//Intermediate Step
        double coralSaddle		 = 1-cbar;						    //Saddle point value for coral
        double macroSaddle		 = (r-r*coralSaddle-d)/(r+a);		//Saddle point value for macroalgae
        double gZero	 = ((d*a*r+d*d)*(gamma-a))/(r*r);
        double gOne		 = (gamma*(a+d))/(a+r);
        double omega	 = sqrt((r*r*(g*g-gZero*gZero))/(d*d));
        double tauZero	 = (1/omega)*acos(gZero/g);

        double dt        = .0001;          // Set the initial time step
        long   numberDT;    // The current iteration for the number assocated with the value of dt.
        double final;       // The final time for each simulation.
        long   trials;      // The number of simulations to make.

        final=50;  // Set the final time.
        trials=400; // Set the number of trials to perform.

        // Set the time delay, tau
        double tau = 0.5;

        // set up the variables for using different approximations on different threads.
        std::thread simulation[NUMBER_THREADS];
        int numberThreads = 0;

        // Sets the seed for the random numbers
        srand(time(NULL));

        // Create a CSV File
        std::ofstream fp;
                //String fileName = "trials-g" + std::toString(g) + "-tau" + std::toString(tau);
        fp.open(OUTPUT_FILE,std::ios::out | std::ios::trunc);

        fp << "dt,beta,g,tau,trial,theta,initMacro,initCoral,initTurf,macroalgae,coral,turf,lgMacro,lgCoral,lgTurf" << std::endl;

/*		for (g=0.1;g<=0.8;g=g+0.02)
            {
                //Redefine initial conditions and critical points for varying g
                cbar		 = (-xi-sqrt(xi*xi-4*chi*g))/(2*chi);
                coralSaddle		 = 1-cbar;
                macroSaddle		 = (r-r*coralSaddle-d)/(r+a);
                omega	 = sqrt((r*r*(g*g-gZero*gZero))/(d*d));
                tauZero	 = (1/omega)*acos(gZero/g);
                if (coralSaddle>0 && coralSaddle<1 && macroSaddle>0 && macroSaddle<1 && tauZero>0)
            for (double aleph=0;aleph<=5;aleph=aleph+1)
            {

                tau=.3*(1+aleph)*tauZero;
                dt=0.0001;
*/

           // Determine the number of time steps required to move back to the delay in time.
           // The number of cells needed for the delay (changes with dt)
            int n;
            n=(int)(tau/BASE_DT+0.5);

            // Allocate the space for the states of the system
            x=(double *) calloc(4,sizeof(double));
            y=(double *) calloc(n,sizeof(double));		//macroalgae for multiplicative noise
            z=(double *) calloc(n,sizeof(double));		//coral for multiplicative noise
            v=(double *) calloc(n,sizeof(double));		//macroalgae for logistic noise
            w=(double *) calloc(n,sizeof(double));		//coral for logistic noise

            //for(numberDT=1;numberDT<5;++numberDT)
                    dt = BASE_DT; //(double)numberDT;
                    //printf("%f\t%f\n",dt,fmod(tau,dt));

            // Make different approximations for different values for the time steps.
            for(beta=.1;beta<=.45; beta += .05)
                {
                    //dt = BASE_DT*(double)numberDT;
#ifdef SHOW_PROGRESS
                    std::cout << "dt = " << dt << std::endl;
#endif
                    if ((int)(10000.0*tau+.5)%(int)(dt*10000.0+.5)==0)
                    {
                        //index = tau/dt;
                        n=(int)(tau/dt+.5);
                        //printf("%i\n",n);
                        steps=(long)(final/dt);

                        // Make an approximation for different initial conditions.
                        // Make an arc through 0 to pi/2 radians from the origin.
                        for (double theta=0;theta<=M_PI/2;theta+=(M_PI*0.5)*0.05)
                        {
                            for (int k=0;k<trials;k++)
                            {
                                y[0]=0.06*cos(theta); //initial Macroalgae level
                                z[0]=0.06*sin(theta); //initial Coral level
                                v[0]=0.06*cos(theta);
                                w[0]=0.06*sin(theta);
                                for (int l=1;l<n;l++) //fills in the past times for y, z, v, and w
                                {
                                    y[l]=y[0];
                                    z[l]=z[0];
                                    v[l]=v[0];
                                    w[l]=w[0];
                                }
                                //fprintf(fp,"%f,%f,%f,%f,%f,%f\n",y[0],z[0],1-y[0]-z[0],v[0],w[0],1-v[0]-w[0]);
#ifdef USE_MULTIPLE_THREADS

                                // Make a simulation for each of the available threads.
                                // First check to see how many threads are running.
                                if(numberThreads >= NUMBER_THREADS)
                                {
                                    // There are too many threads. Wait for each run to end.
                                    while(numberThreads>0)
                                    {
#ifdef THREAD_DEBUG
                                        std::cout << "Waiting on thread "
                                                  << simulation[numberThreads-1].get_id()
                                                  << std::endl;
#endif
                                        simulation[--numberThreads].join();
                                    }
                                }

                                // Make a run in a separate thread.
                                simulation[numberThreads++] = std::thread(linear,
                                                                          steps,a,gamma,r,d,g,x,y,z,dt,n,beta,tau,&fp,k,y[0],z[0],v,w,theta);

#else

                                // Ignore the different threads. Just make one approximation in this one thread.
                                linear(steps,a,gamma,r,d,g,x,y,z,dt,n,beta,tau,&fp,k,y[0],z[0],v,w,theta);

#endif

#ifdef SHOW_PROGRESS
                                if(k%20 == 0)
                                    std::cout << "  Simulation number " << k << std::endl;
#endif

                            }
                        }
            }

            // Free up the allocated memory.
            free(x);
            free(y);
            free(z);
            free(v);
            free(w);
            //}
            //}

        fp.close();

#ifdef SHOW_PROGRESS
            std::cout << "all done" << std::endl;
#endif

        return b.exec();
}
<|endoftext|>