<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 "SkTwoPointConicalGradient.h"

#include "SkRasterPipeline.h"
#include "../../jumper/SkJumper.h"

sk_sp<SkShader> SkTwoPointConicalGradient::Create(const SkPoint& c0, SkScalar r0,
                                                  const SkPoint& c1, SkScalar r1,
                                                  bool flipped, const Descriptor& desc) {
    SkMatrix gradientMatrix;
    Type     gradientType;

    if (SkScalarNearlyZero((c0 - c1).length())) {
        // Concentric case: we can pretend we're radial (with a tiny twist).
        gradientMatrix = SkMatrix::MakeTrans(-c1.x(), -c1.y());
        gradientMatrix.postScale(1 / r1, 1 / r1);

        gradientType = Type::kRadial;
    } else {
        const SkPoint centers[2] = { c0    , c1     };
        const SkPoint unitvec[2] = { {0, 0}, {1, 0} };

        if (!gradientMatrix.setPolyToPoly(centers, unitvec, 2)) {
            // Degenerate case.
            return nullptr;
        }

        // General two-point case.
        gradientType = Type::kTwoPoint;
    }

    return sk_sp<SkShader>(new SkTwoPointConicalGradient(c0, r0, c1, r1, flipped, desc,
                                                         gradientType, gradientMatrix));
}

SkTwoPointConicalGradient::SkTwoPointConicalGradient(
        const SkPoint& start, SkScalar startRadius,
        const SkPoint& end, SkScalar endRadius,
        bool flippedGrad, const Descriptor& desc,
        Type type, const SkMatrix& gradientMatrix)
    : SkGradientShaderBase(desc, gradientMatrix)
    , fCenter1(start)
    , fCenter2(end)
    , fRadius1(startRadius)
    , fRadius2(endRadius)
    , fFlippedGrad(flippedGrad)
    , fType(type)
{
    // this is degenerate, and should be caught by our caller
    SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
}

bool SkTwoPointConicalGradient::isOpaque() const {
    // Because areas outside the cone are left untouched, we cannot treat the
    // shader as opaque even if the gradient itself is opaque.
    // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
    return false;
}

// Returns the original non-sorted version of the gradient
SkShader::GradientType SkTwoPointConicalGradient::asAGradient(
    GradientInfo* info) const {
    if (info) {
        commonAsAGradient(info, fFlippedGrad);
        info->fPoint[0] = fCenter1;
        info->fPoint[1] = fCenter2;
        info->fRadius[0] = fRadius1;
        info->fRadius[1] = fRadius2;
        if (fFlippedGrad) {
            SkTSwap(info->fPoint[0], info->fPoint[1]);
            SkTSwap(info->fRadius[0], info->fRadius[1]);
        }
    }
    return kConical_GradientType;
}

sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) {
    DescriptorScope desc;
    if (!desc.unflatten(buffer)) {
        return nullptr;
    }
    SkPoint c1 = buffer.readPoint();
    SkPoint c2 = buffer.readPoint();
    SkScalar r1 = buffer.readScalar();
    SkScalar r2 = buffer.readScalar();

    if (buffer.readBool()) {    // flipped
        SkTSwap(c1, c2);
        SkTSwap(r1, r2);

        SkColor4f* colors = desc.mutableColors();
        SkScalar* pos = desc.mutablePos();
        const int last = desc.fCount - 1;
        const int half = desc.fCount >> 1;
        for (int i = 0; i < half; ++i) {
            SkTSwap(colors[i], colors[last - i]);
            if (pos) {
                SkScalar tmp = pos[i];
                pos[i] = SK_Scalar1 - pos[last - i];
                pos[last - i] = SK_Scalar1 - tmp;
            }
        }
        if (pos) {
            if (desc.fCount & 1) {
                pos[half] = SK_Scalar1 - pos[half];
            }
        }
    }

    return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
                                                 std::move(desc.fColorSpace), desc.fPos,
                                                 desc.fCount, desc.fTileMode, desc.fGradFlags,
                                                 desc.fLocalMatrix);
}

void SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writePoint(fCenter1);
    buffer.writePoint(fCenter2);
    buffer.writeScalar(fRadius1);
    buffer.writeScalar(fRadius2);
    buffer.writeBool(fFlippedGrad);
}

#if SK_SUPPORT_GPU

#include "SkGr.h"
#include "SkTwoPointConicalGradient_gpu.h"

sk_sp<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
        const AsFPArgs& args) const {
    SkASSERT(args.fContext);
    SkASSERT(fPtsToUnit.isIdentity());
    sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
                                                                       args.fDstColorSpace);
    sk_sp<GrFragmentProcessor> inner(Gr2PtConicalGradientEffect::Make(
        GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
                                     std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
    if (!inner) {
        return nullptr;
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
}

#endif

sk_sp<SkShader> SkTwoPointConicalGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    SkSTArray<8, SkColor> origColorsStorage(fColorCount);
    SkSTArray<8, SkScalar> origPosStorage(fColorCount);
    SkSTArray<8, SkColor> xformedColorsStorage(fColorCount);
    SkColor* origColors = origColorsStorage.begin();
    SkScalar* origPos = fOrigPos ? origPosStorage.begin() : nullptr;
    SkColor* xformedColors = xformedColorsStorage.begin();

    // Flip if necessary
    SkPoint center1 = fFlippedGrad ? fCenter2 : fCenter1;
    SkPoint center2 = fFlippedGrad ? fCenter1 : fCenter2;
    SkScalar radius1 = fFlippedGrad ? fRadius2 : fRadius1;
    SkScalar radius2 = fFlippedGrad ? fRadius1 : fRadius2;
    for (int i = 0; i < fColorCount; i++) {
        origColors[i] = fFlippedGrad ? fOrigColors[fColorCount - i - 1] : fOrigColors[i];
        if (origPos) {
            origPos[i] = fFlippedGrad ? 1.0f - fOrigPos[fColorCount - i - 1] : fOrigPos[i];
        }
    }

    xformer->apply(xformedColors, origColors, fColorCount);
    return SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, xformedColors,
                                                 origPos, fColorCount, fTileMode, fGradFlags,
                                                 &this->getLocalMatrix());
}

#ifndef SK_IGNORE_TO_STRING
void SkTwoPointConicalGradient::toString(SkString* str) const {
    str->append("SkTwoPointConicalGradient: (");

    str->append("center1: (");
    str->appendScalar(fCenter1.fX);
    str->append(", ");
    str->appendScalar(fCenter1.fY);
    str->append(") radius1: ");
    str->appendScalar(fRadius1);
    str->append(" ");

    str->append("center2: (");
    str->appendScalar(fCenter2.fX);
    str->append(", ");
    str->appendScalar(fCenter2.fY);
    str->append(") radius2: ");
    str->appendScalar(fRadius2);
    str->append(" ");

    this->INHERITED::toString(str);

    str->append(")");
}
#endif

bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
                                                            SkMatrix* matrix,
                                                            SkRasterPipeline* p,
                                                            SkRasterPipeline* postPipeline) const {
    matrix->postConcat(fPtsToUnit);

    const auto dRadius = fRadius2 - fRadius1;
    SkASSERT(dRadius >= 0);

    if (fType == Type::kRadial) {
        p->append(SkRasterPipeline::xy_to_radius);

        // Tiny twist: radial computes a t for [0, r2], but we want a t for [r1, r2].
        auto scale =  fRadius2 / dRadius;
        auto bias  = -fRadius1 / dRadius;

        p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeTrans(bias, 0),
                                                 SkMatrix::MakeScale(scale, 1)));

        return true;
    }

    const auto dCenter = (fCenter1 - fCenter2).length();

    // Since we've squashed the centers into a unit vector, we must also scale
    // all the coefficient variables by (1 / dCenter).
    const auto coeffA = 1 - dRadius * dRadius / (dCenter * dCenter);
    auto* ctx = alloc->make<SkJumper_2PtConicalCtx>();
    ctx->fCoeffA    = coeffA;
    ctx->fInvCoeffA = 1 / coeffA;
    ctx->fR0        = fRadius1 / dCenter;
    ctx->fDR        = dRadius  / dCenter;

    // Is the solver guaranteed to not produce degenerates?
    bool isWellBehaved = true;

    if (SkScalarNearlyZero(coeffA)) {
        // The focal point is on the edge of the end circle.
        p->append(SkRasterPipeline::xy_to_2pt_conical_linear, ctx);
        isWellBehaved = false;
    } else {
        if (dCenter + fRadius1 > fRadius2) {
            // The focal point is outside the end circle.

            // We want the larger root, per spec:
            //   "For all values of ω where r(ω) > 0, starting with the value of ω nearest
            //    to positive infinity and ending with the value of ω nearest to negative
            //    infinity, draw the circumference of the circle with radius r(ω) at position
            //    (x(ω), y(ω)), with the color at ω, but only painting on the parts of the
            //    bitmap that have not yet been painted on by earlier circles in this step for
            //    this rendering of the gradient."
            // (https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createradialgradient)
            p->append(fFlippedGrad ? SkRasterPipeline::xy_to_2pt_conical_quadratic_min
                                   : SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx);
            isWellBehaved = false;
        } else {
            // The focal point is inside (well-behaved case).
            p->append(SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx);
        }
    }

    if (!isWellBehaved) {
        p->append(SkRasterPipeline::mask_2pt_conical_degenerates, ctx);
        postPipeline->append(SkRasterPipeline::apply_vector_mask, &ctx->fMask);
    }

    return true;
}
<commit_msg>Remove stale SkTwoPointConicalGradient assert<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 "SkTwoPointConicalGradient.h"

#include "SkRasterPipeline.h"
#include "../../jumper/SkJumper.h"

sk_sp<SkShader> SkTwoPointConicalGradient::Create(const SkPoint& c0, SkScalar r0,
                                                  const SkPoint& c1, SkScalar r1,
                                                  bool flipped, const Descriptor& desc) {
    SkMatrix gradientMatrix;
    Type     gradientType;

    if (SkScalarNearlyZero((c0 - c1).length())) {
        // Concentric case: we can pretend we're radial (with a tiny twist).
        gradientMatrix = SkMatrix::MakeTrans(-c1.x(), -c1.y());
        gradientMatrix.postScale(1 / r1, 1 / r1);

        gradientType = Type::kRadial;
    } else {
        const SkPoint centers[2] = { c0    , c1     };
        const SkPoint unitvec[2] = { {0, 0}, {1, 0} };

        if (!gradientMatrix.setPolyToPoly(centers, unitvec, 2)) {
            // Degenerate case.
            return nullptr;
        }

        // General two-point case.
        gradientType = Type::kTwoPoint;
    }

    return sk_sp<SkShader>(new SkTwoPointConicalGradient(c0, r0, c1, r1, flipped, desc,
                                                         gradientType, gradientMatrix));
}

SkTwoPointConicalGradient::SkTwoPointConicalGradient(
        const SkPoint& start, SkScalar startRadius,
        const SkPoint& end, SkScalar endRadius,
        bool flippedGrad, const Descriptor& desc,
        Type type, const SkMatrix& gradientMatrix)
    : SkGradientShaderBase(desc, gradientMatrix)
    , fCenter1(start)
    , fCenter2(end)
    , fRadius1(startRadius)
    , fRadius2(endRadius)
    , fFlippedGrad(flippedGrad)
    , fType(type)
{
    // this is degenerate, and should be caught by our caller
    SkASSERT(fCenter1 != fCenter2 || fRadius1 != fRadius2);
}

bool SkTwoPointConicalGradient::isOpaque() const {
    // Because areas outside the cone are left untouched, we cannot treat the
    // shader as opaque even if the gradient itself is opaque.
    // TODO(junov): Compute whether the cone fills the plane crbug.com/222380
    return false;
}

// Returns the original non-sorted version of the gradient
SkShader::GradientType SkTwoPointConicalGradient::asAGradient(
    GradientInfo* info) const {
    if (info) {
        commonAsAGradient(info, fFlippedGrad);
        info->fPoint[0] = fCenter1;
        info->fPoint[1] = fCenter2;
        info->fRadius[0] = fRadius1;
        info->fRadius[1] = fRadius2;
        if (fFlippedGrad) {
            SkTSwap(info->fPoint[0], info->fPoint[1]);
            SkTSwap(info->fRadius[0], info->fRadius[1]);
        }
    }
    return kConical_GradientType;
}

sk_sp<SkFlattenable> SkTwoPointConicalGradient::CreateProc(SkReadBuffer& buffer) {
    DescriptorScope desc;
    if (!desc.unflatten(buffer)) {
        return nullptr;
    }
    SkPoint c1 = buffer.readPoint();
    SkPoint c2 = buffer.readPoint();
    SkScalar r1 = buffer.readScalar();
    SkScalar r2 = buffer.readScalar();

    if (buffer.readBool()) {    // flipped
        SkTSwap(c1, c2);
        SkTSwap(r1, r2);

        SkColor4f* colors = desc.mutableColors();
        SkScalar* pos = desc.mutablePos();
        const int last = desc.fCount - 1;
        const int half = desc.fCount >> 1;
        for (int i = 0; i < half; ++i) {
            SkTSwap(colors[i], colors[last - i]);
            if (pos) {
                SkScalar tmp = pos[i];
                pos[i] = SK_Scalar1 - pos[last - i];
                pos[last - i] = SK_Scalar1 - tmp;
            }
        }
        if (pos) {
            if (desc.fCount & 1) {
                pos[half] = SK_Scalar1 - pos[half];
            }
        }
    }

    return SkGradientShader::MakeTwoPointConical(c1, r1, c2, r2, desc.fColors,
                                                 std::move(desc.fColorSpace), desc.fPos,
                                                 desc.fCount, desc.fTileMode, desc.fGradFlags,
                                                 desc.fLocalMatrix);
}

void SkTwoPointConicalGradient::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writePoint(fCenter1);
    buffer.writePoint(fCenter2);
    buffer.writeScalar(fRadius1);
    buffer.writeScalar(fRadius2);
    buffer.writeBool(fFlippedGrad);
}

#if SK_SUPPORT_GPU

#include "SkGr.h"
#include "SkTwoPointConicalGradient_gpu.h"

sk_sp<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
        const AsFPArgs& args) const {
    SkASSERT(args.fContext);
    sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
                                                                       args.fDstColorSpace);
    sk_sp<GrFragmentProcessor> inner(Gr2PtConicalGradientEffect::Make(
        GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
                                     std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
    if (!inner) {
        return nullptr;
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
}

#endif

sk_sp<SkShader> SkTwoPointConicalGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    SkSTArray<8, SkColor> origColorsStorage(fColorCount);
    SkSTArray<8, SkScalar> origPosStorage(fColorCount);
    SkSTArray<8, SkColor> xformedColorsStorage(fColorCount);
    SkColor* origColors = origColorsStorage.begin();
    SkScalar* origPos = fOrigPos ? origPosStorage.begin() : nullptr;
    SkColor* xformedColors = xformedColorsStorage.begin();

    // Flip if necessary
    SkPoint center1 = fFlippedGrad ? fCenter2 : fCenter1;
    SkPoint center2 = fFlippedGrad ? fCenter1 : fCenter2;
    SkScalar radius1 = fFlippedGrad ? fRadius2 : fRadius1;
    SkScalar radius2 = fFlippedGrad ? fRadius1 : fRadius2;
    for (int i = 0; i < fColorCount; i++) {
        origColors[i] = fFlippedGrad ? fOrigColors[fColorCount - i - 1] : fOrigColors[i];
        if (origPos) {
            origPos[i] = fFlippedGrad ? 1.0f - fOrigPos[fColorCount - i - 1] : fOrigPos[i];
        }
    }

    xformer->apply(xformedColors, origColors, fColorCount);
    return SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2, xformedColors,
                                                 origPos, fColorCount, fTileMode, fGradFlags,
                                                 &this->getLocalMatrix());
}

#ifndef SK_IGNORE_TO_STRING
void SkTwoPointConicalGradient::toString(SkString* str) const {
    str->append("SkTwoPointConicalGradient: (");

    str->append("center1: (");
    str->appendScalar(fCenter1.fX);
    str->append(", ");
    str->appendScalar(fCenter1.fY);
    str->append(") radius1: ");
    str->appendScalar(fRadius1);
    str->append(" ");

    str->append("center2: (");
    str->appendScalar(fCenter2.fX);
    str->append(", ");
    str->appendScalar(fCenter2.fY);
    str->append(") radius2: ");
    str->appendScalar(fRadius2);
    str->append(" ");

    this->INHERITED::toString(str);

    str->append(")");
}
#endif

bool SkTwoPointConicalGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc,
                                                            SkMatrix* matrix,
                                                            SkRasterPipeline* p,
                                                            SkRasterPipeline* postPipeline) const {
    matrix->postConcat(fPtsToUnit);

    const auto dRadius = fRadius2 - fRadius1;
    SkASSERT(dRadius >= 0);

    if (fType == Type::kRadial) {
        p->append(SkRasterPipeline::xy_to_radius);

        // Tiny twist: radial computes a t for [0, r2], but we want a t for [r1, r2].
        auto scale =  fRadius2 / dRadius;
        auto bias  = -fRadius1 / dRadius;

        p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeTrans(bias, 0),
                                                 SkMatrix::MakeScale(scale, 1)));

        return true;
    }

    const auto dCenter = (fCenter1 - fCenter2).length();

    // Since we've squashed the centers into a unit vector, we must also scale
    // all the coefficient variables by (1 / dCenter).
    const auto coeffA = 1 - dRadius * dRadius / (dCenter * dCenter);
    auto* ctx = alloc->make<SkJumper_2PtConicalCtx>();
    ctx->fCoeffA    = coeffA;
    ctx->fInvCoeffA = 1 / coeffA;
    ctx->fR0        = fRadius1 / dCenter;
    ctx->fDR        = dRadius  / dCenter;

    // Is the solver guaranteed to not produce degenerates?
    bool isWellBehaved = true;

    if (SkScalarNearlyZero(coeffA)) {
        // The focal point is on the edge of the end circle.
        p->append(SkRasterPipeline::xy_to_2pt_conical_linear, ctx);
        isWellBehaved = false;
    } else {
        if (dCenter + fRadius1 > fRadius2) {
            // The focal point is outside the end circle.

            // We want the larger root, per spec:
            //   "For all values of ω where r(ω) > 0, starting with the value of ω nearest
            //    to positive infinity and ending with the value of ω nearest to negative
            //    infinity, draw the circumference of the circle with radius r(ω) at position
            //    (x(ω), y(ω)), with the color at ω, but only painting on the parts of the
            //    bitmap that have not yet been painted on by earlier circles in this step for
            //    this rendering of the gradient."
            // (https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createradialgradient)
            p->append(fFlippedGrad ? SkRasterPipeline::xy_to_2pt_conical_quadratic_min
                                   : SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx);
            isWellBehaved = false;
        } else {
            // The focal point is inside (well-behaved case).
            p->append(SkRasterPipeline::xy_to_2pt_conical_quadratic_max, ctx);
        }
    }

    if (!isWellBehaved) {
        p->append(SkRasterPipeline::mask_2pt_conical_degenerates, ctx);
        postPipeline->append(SkRasterPipeline::apply_vector_mask, &ctx->fMask);
    }

    return true;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "virtualserialdevice.h"
#include <windows.h>
#include <QtCore/private/qwineventnotifier_p.h>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

namespace SymbianUtils {

class VirtualSerialDevicePrivate
{
public:
    HANDLE portHandle;
    OVERLAPPED writeOverlapped;
    OVERLAPPED commEventOverlapped;
    DWORD commEventMask;
    QWinEventNotifier *writeCompleteNotifier;
    QWinEventNotifier *commEventNotifier;
};

void VirtualSerialDevice::platInit()
{
    d = new VirtualSerialDevicePrivate;
    d->portHandle = INVALID_HANDLE_VALUE;
    d->writeCompleteNotifier = NULL;
    memset(&d->writeOverlapped, 0, sizeof(OVERLAPPED));
    d->commEventNotifier = NULL;
    memset(&d->commEventOverlapped, 0, sizeof(OVERLAPPED));
}

QString windowsPortName(const QString& port)
{
    // Add the \\.\ to the name if it's a COM port and doesn't already have it
    QString winPortName(port);
    if (winPortName.startsWith(QLatin1String("COM"))) {
        winPortName.prepend("\\\\.\\");
    }
    return winPortName;
}

// Copied from \creator\src\libs\utils\winutils.cpp
QString winErrorMessage(unsigned long error)
{
    // Some of the windows error messages are a bit too obscure
    switch (error)
        {
    case ERROR_FILE_NOT_FOUND:
    case ERROR_NOT_FOUND:
        return VirtualSerialDevice::tr("Port not found");
        break;
    case ERROR_ACCESS_DENIED:
        return VirtualSerialDevice::tr("Port in use");
    case ERROR_SEM_TIMEOUT: // Bluetooth ports sometimes return this
        return VirtualSerialDevice::tr("Timed out");
    case ERROR_NETWORK_UNREACHABLE:
        return VirtualSerialDevice::tr("Port unreachable"); // I don't know what this error indicates... from observation, that the windows Bluetooth stack has got itself into a state and needs resetting
    default:
        break;
        }

    QString rc = QString::fromLatin1("#%1: ").arg(error);
    ushort *lpMsgBuf;

    const int len = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
    if (len) {
        rc = QString::fromUtf16(lpMsgBuf, len);
        LocalFree(lpMsgBuf);
    } else {
        rc += QString::fromLatin1("<unknown error>");
    }
    return rc.trimmed();
}

bool VirtualSerialDevice::open(OpenMode mode)
{
    Q_ASSERT(QThread::currentThread() == thread());
    if (isOpen()) return true;

    d->portHandle = CreateFileA(windowsPortName(portName).toAscii(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (d->portHandle == INVALID_HANDLE_VALUE) {
        setErrorString(tr("The port %1 could not be opened: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        return false;
    }

    DCB commState;
    memset(&commState, 0, sizeof(DCB));
    commState.DCBlength = sizeof(DCB);
    bool ok = GetCommState(d->portHandle, &commState);
    if (ok) {
        commState.BaudRate = CBR_115200;
        commState.fBinary = TRUE;
        commState.fParity = FALSE;
        commState.fOutxCtsFlow = FALSE;
        commState.fOutxDsrFlow = FALSE;
        commState.fInX = FALSE;
        commState.fOutX = FALSE;
        commState.fNull = FALSE;
        commState.fAbortOnError = FALSE;
        commState.fDsrSensitivity = FALSE;
        commState.fDtrControl = DTR_CONTROL_DISABLE;
        commState.ByteSize = 8;
        commState.Parity = NOPARITY;
        commState.StopBits = ONESTOPBIT;
        ok = SetCommState(d->portHandle, &commState);
    }
    if (!ok) {
        qWarning("%s setting comm state", qPrintable(winErrorMessage(GetLastError())));
    }

    // http://msdn.microsoft.com/en-us/library/aa363190(v=vs.85).aspx says this means
    // "the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received"
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts(d->portHandle, &timeouts);

    d->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->writeCompleteNotifier = new QWinEventNotifier(d->writeOverlapped.hEvent, this);
    connect(d->writeCompleteNotifier, SIGNAL(activated(HANDLE)), this, SLOT(writeCompleted()));

    // This is how we implement readyRead notifications
    d->commEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->commEventNotifier = new QWinEventNotifier(d->commEventOverlapped.hEvent, this);
    connect(d->commEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(commEventOccurred()));

    if (!SetCommMask(d->portHandle, EV_RXCHAR)) {
        // What to do?
        qWarning("%s: Could not set comm mask, err=%d", Q_FUNC_INFO, (int)GetLastError());
    }
    bool result = WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped);
    Q_ASSERT(result == false); // Can't see how it would make sense to be anything else...
    (void)result; // For release build
    if (GetLastError() != ERROR_IO_PENDING) {
        setErrorString(tr("An error occurred while waiting for read notifications from %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        close();
        return false;
    }

    ok = QIODevice::open(mode);
    if (!ok) close();
    return ok;
}

void VirtualSerialDevice::platClose()
{
    delete d->writeCompleteNotifier;
    d->writeCompleteNotifier = NULL;
    CloseHandle(d->writeOverlapped.hEvent);
    d->writeOverlapped.hEvent = INVALID_HANDLE_VALUE;

    delete d->commEventNotifier;
    d->commEventNotifier = NULL;
    d->commEventOverlapped.hEvent = INVALID_HANDLE_VALUE;

    CloseHandle(d->portHandle);
    d->portHandle = INVALID_HANDLE_VALUE;
}

VirtualSerialDevice::~VirtualSerialDevice()
{
    close();
    delete d;
}

qint64 VirtualSerialDevice::bytesAvailable() const
{
    QMutexLocker locker(&lock);
    if (!isOpen()) return 0;

    qint64 avail = 0;
    COMSTAT Status;
    if (ClearCommError(d->portHandle, NULL, &Status)) {
        avail = Status.cbInQue;
    }
    return avail + QIODevice::bytesAvailable();
}

void VirtualSerialDevice::commEventOccurred()
{
    DWORD event = d->commEventMask;
    if (event & EV_RXCHAR) {
        emit readyRead();
    }
    ResetEvent(d->commEventOverlapped.hEvent);
    WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped);
}

qint64 VirtualSerialDevice::readData(char *data, qint64 maxSize)
{
    QMutexLocker locker(&lock);
    // We do our reads synchronously
    OVERLAPPED readOverlapped;
    memset(&readOverlapped, 0, sizeof(OVERLAPPED));
    DWORD bytesRead;
    BOOL done = ReadFile(d->portHandle, data, maxSize, &bytesRead, &readOverlapped);
    if (done) return (qint64)bytesRead;

    if (GetLastError() == ERROR_IO_PENDING) {
        // Note the TRUE to wait for the read to complete
        done = GetOverlappedResult(d->portHandle, &readOverlapped, &bytesRead, TRUE);
        if (done) return (qint64)bytesRead;
    }

    // If we reach here an error has occurred
    setErrorString(tr("An error occurred while reading from %1: %2").
                   arg(portName, winErrorMessage(GetLastError())));
    return -1;
}

qint64 VirtualSerialDevice::writeData(const char *data, qint64 maxSize)
{
    QMutexLocker locker(&lock);

    pendingWrites.append(QByteArray(data, maxSize)); // Can't see a way of doing async io safely without having to copy here...
    if (pendingWrites.count() == 1) {
        return writeNextBuffer(locker);
    } else {
        return maxSize;
    }
}

qint64 VirtualSerialDevice::writeNextBuffer(QMutexLocker& locker)
{
    Q_UNUSED(locker)
    // Must be locked on entry
    qint64 bufLen = pendingWrites[0].length();
    BOOL ok = WriteFile(d->portHandle, pendingWrites[0].constData(), bufLen, NULL, &d->writeOverlapped);
    if (ok || GetLastError() == ERROR_IO_PENDING) {
        // Apparently it can return true for a small asynchronous write...
        // Hopefully it still gets signalled in the same way!

        // Wait for signal via writeCompleted
        return bufLen;
    }
    else {
        setErrorString(tr("An error occurred while writing to %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        pendingWrites.removeFirst();
        return -1;
    }
}

void VirtualSerialDevice::writeCompleted()
{
    QMutexLocker locker(&lock);
    if (pendingWrites.count() == 0) {
        qWarning("%s: writeCompleted called when there are no pending writes on %s!",
                 Q_FUNC_INFO, qPrintable(portName));
        return;
    }

    doWriteCompleted(locker);
}

void VirtualSerialDevice::doWriteCompleted(QMutexLocker &locker)
{
    // Must be locked on entry
    ResetEvent(d->writeOverlapped.hEvent);

    qint64 len = pendingWrites.first().length();
    pendingWrites.removeFirst();

    if (pendingWrites.count() > 0) {
        // Get the next write started before notifying in case client calls waitForBytesWritten in their slot
        writeNextBuffer(locker);
    }

    emitBytesWrittenIfNeeded(locker, len);
}

bool VirtualSerialDevice::waitForBytesWritten(int msecs)
{
    QMutexLocker locker(&lock);
    if (pendingWrites.count() == 0) return false;

    if (QThread::currentThread() != thread()) {
        // Wait for signal from main thread
        unsigned long timeout = msecs;
        if (msecs == -1) timeout = ULONG_MAX;
        if (waiterForBytesWritten == NULL)
            waiterForBytesWritten = new QWaitCondition;
        return waiterForBytesWritten->wait(&lock, timeout);
    }

    DWORD waitTime = msecs;
    if (msecs == -1) waitTime = INFINITE; // Ok these are probably bitwise the same, but just to prove I've thought about it...
    DWORD result = WaitForSingleObject(d->writeOverlapped.hEvent, waitTime); // Do I need WaitForSingleObjectEx and worry about alertable states?
    if (result == WAIT_TIMEOUT) {
        return false;
    }
    else if (result == WAIT_OBJECT_0) {
        DWORD bytesWritten;
        BOOL ok = GetOverlappedResult(d->portHandle, &d->writeOverlapped, &bytesWritten, TRUE);
        if (!ok) {
            setErrorString(tr("An error occurred while syncing on waitForBytesWritten for %1: %2").
                           arg(portName, winErrorMessage(GetLastError())));
            return false;
        }
        Q_ASSERT(bytesWritten == (DWORD)pendingWrites.first().length());

        doWriteCompleted(locker);
        return true;
    }
    else {
        setErrorString(QString("An error occured in waitForBytesWritten() for %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        return false;
    }
}

void VirtualSerialDevice::flush()
{
    while (waitForBytesWritten(-1)) { /* loop */ }
}

bool VirtualSerialDevice::waitForReadyRead(int msecs)
{
    return QIODevice::waitForReadyRead(msecs); //TODO
}

} // namespace SymbianUtils
<commit_msg>Typo fixed<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "virtualserialdevice.h"
#include <windows.h>
#include <QtCore/private/qwineventnotifier_p.h>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

namespace SymbianUtils {

class VirtualSerialDevicePrivate
{
public:
    HANDLE portHandle;
    OVERLAPPED writeOverlapped;
    OVERLAPPED commEventOverlapped;
    DWORD commEventMask;
    QWinEventNotifier *writeCompleteNotifier;
    QWinEventNotifier *commEventNotifier;
};

void VirtualSerialDevice::platInit()
{
    d = new VirtualSerialDevicePrivate;
    d->portHandle = INVALID_HANDLE_VALUE;
    d->writeCompleteNotifier = NULL;
    memset(&d->writeOverlapped, 0, sizeof(OVERLAPPED));
    d->commEventNotifier = NULL;
    memset(&d->commEventOverlapped, 0, sizeof(OVERLAPPED));
}

QString windowsPortName(const QString& port)
{
    // Add the \\.\ to the name if it's a COM port and doesn't already have it
    QString winPortName(port);
    if (winPortName.startsWith(QLatin1String("COM"))) {
        winPortName.prepend("\\\\.\\");
    }
    return winPortName;
}

// Copied from \creator\src\libs\utils\winutils.cpp
QString winErrorMessage(unsigned long error)
{
    // Some of the windows error messages are a bit too obscure
    switch (error)
        {
    case ERROR_FILE_NOT_FOUND:
    case ERROR_NOT_FOUND:
        return VirtualSerialDevice::tr("Port not found");
        break;
    case ERROR_ACCESS_DENIED:
        return VirtualSerialDevice::tr("Port in use");
    case ERROR_SEM_TIMEOUT: // Bluetooth ports sometimes return this
        return VirtualSerialDevice::tr("Timed out");
    case ERROR_NETWORK_UNREACHABLE:
        return VirtualSerialDevice::tr("Port unreachable"); // I don't know what this error indicates... from observation, that the windows Bluetooth stack has got itself into a state and needs resetting
    default:
        break;
        }

    QString rc = QString::fromLatin1("#%1: ").arg(error);
    ushort *lpMsgBuf;

    const int len = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
    if (len) {
        rc = QString::fromUtf16(lpMsgBuf, len);
        LocalFree(lpMsgBuf);
    } else {
        rc += QString::fromLatin1("<unknown error>");
    }
    return rc.trimmed();
}

bool VirtualSerialDevice::open(OpenMode mode)
{
    Q_ASSERT(QThread::currentThread() == thread());
    if (isOpen()) return true;

    d->portHandle = CreateFileA(windowsPortName(portName).toAscii(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (d->portHandle == INVALID_HANDLE_VALUE) {
        setErrorString(tr("The port %1 could not be opened: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        return false;
    }

    DCB commState;
    memset(&commState, 0, sizeof(DCB));
    commState.DCBlength = sizeof(DCB);
    bool ok = GetCommState(d->portHandle, &commState);
    if (ok) {
        commState.BaudRate = CBR_115200;
        commState.fBinary = TRUE;
        commState.fParity = FALSE;
        commState.fOutxCtsFlow = FALSE;
        commState.fOutxDsrFlow = FALSE;
        commState.fInX = FALSE;
        commState.fOutX = FALSE;
        commState.fNull = FALSE;
        commState.fAbortOnError = FALSE;
        commState.fDsrSensitivity = FALSE;
        commState.fDtrControl = DTR_CONTROL_DISABLE;
        commState.ByteSize = 8;
        commState.Parity = NOPARITY;
        commState.StopBits = ONESTOPBIT;
        ok = SetCommState(d->portHandle, &commState);
    }
    if (!ok) {
        qWarning("%s setting comm state", qPrintable(winErrorMessage(GetLastError())));
    }

    // http://msdn.microsoft.com/en-us/library/aa363190(v=vs.85).aspx says this means
    // "the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received"
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts(d->portHandle, &timeouts);

    d->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->writeCompleteNotifier = new QWinEventNotifier(d->writeOverlapped.hEvent, this);
    connect(d->writeCompleteNotifier, SIGNAL(activated(HANDLE)), this, SLOT(writeCompleted()));

    // This is how we implement readyRead notifications
    d->commEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->commEventNotifier = new QWinEventNotifier(d->commEventOverlapped.hEvent, this);
    connect(d->commEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(commEventOccurred()));

    if (!SetCommMask(d->portHandle, EV_RXCHAR)) {
        // What to do?
        qWarning("%s: Could not set comm mask, err=%d", Q_FUNC_INFO, (int)GetLastError());
    }
    bool result = WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped);
    Q_ASSERT(result == false); // Can't see how it would make sense to be anything else...
    (void)result; // For release build
    if (GetLastError() != ERROR_IO_PENDING) {
        setErrorString(tr("An error occurred while waiting for read notifications from %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        close();
        return false;
    }

    ok = QIODevice::open(mode);
    if (!ok) close();
    return ok;
}

void VirtualSerialDevice::platClose()
{
    delete d->writeCompleteNotifier;
    d->writeCompleteNotifier = NULL;
    CloseHandle(d->writeOverlapped.hEvent);
    d->writeOverlapped.hEvent = INVALID_HANDLE_VALUE;

    delete d->commEventNotifier;
    d->commEventNotifier = NULL;
    d->commEventOverlapped.hEvent = INVALID_HANDLE_VALUE;

    CloseHandle(d->portHandle);
    d->portHandle = INVALID_HANDLE_VALUE;
}

VirtualSerialDevice::~VirtualSerialDevice()
{
    close();
    delete d;
}

qint64 VirtualSerialDevice::bytesAvailable() const
{
    QMutexLocker locker(&lock);
    if (!isOpen()) return 0;

    qint64 avail = 0;
    COMSTAT Status;
    if (ClearCommError(d->portHandle, NULL, &Status)) {
        avail = Status.cbInQue;
    }
    return avail + QIODevice::bytesAvailable();
}

void VirtualSerialDevice::commEventOccurred()
{
    DWORD event = d->commEventMask;
    if (event & EV_RXCHAR) {
        emit readyRead();
    }
    ResetEvent(d->commEventOverlapped.hEvent);
    WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped);
}

qint64 VirtualSerialDevice::readData(char *data, qint64 maxSize)
{
    QMutexLocker locker(&lock);
    // We do our reads synchronously
    OVERLAPPED readOverlapped;
    memset(&readOverlapped, 0, sizeof(OVERLAPPED));
    DWORD bytesRead;
    BOOL done = ReadFile(d->portHandle, data, maxSize, &bytesRead, &readOverlapped);
    if (done) return (qint64)bytesRead;

    if (GetLastError() == ERROR_IO_PENDING) {
        // Note the TRUE to wait for the read to complete
        done = GetOverlappedResult(d->portHandle, &readOverlapped, &bytesRead, TRUE);
        if (done) return (qint64)bytesRead;
    }

    // If we reach here an error has occurred
    setErrorString(tr("An error occurred while reading from %1: %2").
                   arg(portName, winErrorMessage(GetLastError())));
    return -1;
}

qint64 VirtualSerialDevice::writeData(const char *data, qint64 maxSize)
{
    QMutexLocker locker(&lock);

    pendingWrites.append(QByteArray(data, maxSize)); // Can't see a way of doing async io safely without having to copy here...
    if (pendingWrites.count() == 1) {
        return writeNextBuffer(locker);
    } else {
        return maxSize;
    }
}

qint64 VirtualSerialDevice::writeNextBuffer(QMutexLocker& locker)
{
    Q_UNUSED(locker)
    // Must be locked on entry
    qint64 bufLen = pendingWrites[0].length();
    BOOL ok = WriteFile(d->portHandle, pendingWrites[0].constData(), bufLen, NULL, &d->writeOverlapped);
    if (ok || GetLastError() == ERROR_IO_PENDING) {
        // Apparently it can return true for a small asynchronous write...
        // Hopefully it still gets signalled in the same way!

        // Wait for signal via writeCompleted
        return bufLen;
    }
    else {
        setErrorString(tr("An error occurred while writing to %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        pendingWrites.removeFirst();
        return -1;
    }
}

void VirtualSerialDevice::writeCompleted()
{
    QMutexLocker locker(&lock);
    if (pendingWrites.count() == 0) {
        qWarning("%s: writeCompleted called when there are no pending writes on %s!",
                 Q_FUNC_INFO, qPrintable(portName));
        return;
    }

    doWriteCompleted(locker);
}

void VirtualSerialDevice::doWriteCompleted(QMutexLocker &locker)
{
    // Must be locked on entry
    ResetEvent(d->writeOverlapped.hEvent);

    qint64 len = pendingWrites.first().length();
    pendingWrites.removeFirst();

    if (pendingWrites.count() > 0) {
        // Get the next write started before notifying in case client calls waitForBytesWritten in their slot
        writeNextBuffer(locker);
    }

    emitBytesWrittenIfNeeded(locker, len);
}

bool VirtualSerialDevice::waitForBytesWritten(int msecs)
{
    QMutexLocker locker(&lock);
    if (pendingWrites.count() == 0) return false;

    if (QThread::currentThread() != thread()) {
        // Wait for signal from main thread
        unsigned long timeout = msecs;
        if (msecs == -1) timeout = ULONG_MAX;
        if (waiterForBytesWritten == NULL)
            waiterForBytesWritten = new QWaitCondition;
        return waiterForBytesWritten->wait(&lock, timeout);
    }

    DWORD waitTime = msecs;
    if (msecs == -1) waitTime = INFINITE; // Ok these are probably bitwise the same, but just to prove I've thought about it...
    DWORD result = WaitForSingleObject(d->writeOverlapped.hEvent, waitTime); // Do I need WaitForSingleObjectEx and worry about alertable states?
    if (result == WAIT_TIMEOUT) {
        return false;
    }
    else if (result == WAIT_OBJECT_0) {
        DWORD bytesWritten;
        BOOL ok = GetOverlappedResult(d->portHandle, &d->writeOverlapped, &bytesWritten, TRUE);
        if (!ok) {
            setErrorString(tr("An error occurred while syncing on waitForBytesWritten for %1: %2").
                           arg(portName, winErrorMessage(GetLastError())));
            return false;
        }
        Q_ASSERT(bytesWritten == (DWORD)pendingWrites.first().length());

        doWriteCompleted(locker);
        return true;
    }
    else {
        setErrorString(QString("An error occurred in waitForBytesWritten() for %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        return false;
    }
}

void VirtualSerialDevice::flush()
{
    while (waitForBytesWritten(-1)) { /* loop */ }
}

bool VirtualSerialDevice::waitForReadyRead(int msecs)
{
    return QIODevice::waitForReadyRead(msecs); //TODO
}

} // namespace SymbianUtils
<|endoftext|>


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

#include "chrome/browser/chromeos/options/wifi_config_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
#include "views/window/window.h"

namespace chromeos {

// The width of the password field.
const int kPasswordWidth = 150;

WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork wifi)
    : parent_(parent),
      other_network_(false),
      can_login_(false),
      wifi_(wifi),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::WifiConfigView(NetworkConfigView* parent)
    : parent_(parent),
      other_network_(true),
      can_login_(false),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

void WifiConfigView::UpdateCanLogin(void) {
  bool can_login = true;
  if (other_network_) {
    // Since the user can try to connect to a non-encrypted hidden network,
    // only enforce ssid is non-empty.
    can_login = !ssid_textfield_->text().empty();
  } else {
    // Connecting to an encrypted network
    if (passphrase_textfield_ != NULL) {
      // if the network requires a passphrase, make sure it is non empty.
      can_login &= !passphrase_textfield_->text().empty();
    }
    if (identity_textfield_ != NULL) {
      // If we have an identity field, we can login if we have a non empty
      // identity and a certificate path
      can_login &= !identity_textfield_->text().empty() &&
          !certificate_path_.empty();
    }
  }

  // Update the login button enable/disable state if can_login_ changes.
  if (can_login != can_login_) {
    can_login_ = can_login;
    parent_->GetDialogClientView()->UpdateDialogButtons();
  }
}

void WifiConfigView::ContentsChanged(views::Textfield* sender,
                                     const string16& new_contents) {
  UpdateCanLogin();
}

void WifiConfigView::ButtonPressed(views::Button* sender,
                                   const views::Event& event) {
  if (sender == passphrase_visible_button_) {
    if (passphrase_textfield_)
      passphrase_textfield_->SetPassword(!passphrase_textfield_->IsPassword());
  } else if (sender == certificate_browse_button_) {
    select_file_dialog_ = SelectFileDialog::Create(this);
    select_file_dialog_->set_browser_mode(parent_->is_browser_mode());
    select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
                                    string16(), FilePath(), NULL, 0,
                                    std::string(),
                                    parent_->is_browser_mode() ?
                                        NULL :
                                        parent_->GetNativeWindow(),
                                    NULL);
  } else {
    NOTREACHED();
  }
}

void WifiConfigView::FileSelected(const FilePath& path,
                                   int index, void* params) {
  certificate_path_ = path.value();
  if (certificate_browse_button_)
    certificate_browse_button_->SetLabel(path.BaseName().ToWStringHack());
  UpdateCanLogin();  // TODO(njw) Check if the passphrase decrypts the key.
}

bool WifiConfigView::Login() {
  std::string identity_string;
  if (identity_textfield_ != NULL) {
    identity_string = UTF16ToUTF8(identity_textfield_->text());
  }
  if (other_network_) {
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        GetSSID(), GetPassphrase(),
        identity_string, certificate_path_,
        autoconnect_checkbox_->checked());
  } else {
    Save();
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        wifi_, GetPassphrase(),
        identity_string, certificate_path_);
  }
  return true;
}

bool WifiConfigView::Save() {
  // Save password and auto-connect here.
  if (!other_network_) {
    bool changed = false;

    bool auto_connect = autoconnect_checkbox_->checked();
    if (auto_connect != wifi_.auto_connect()) {
      wifi_.set_auto_connect(auto_connect);
      changed = true;
    }

    if (passphrase_textfield_) {
      const std::string& passphrase =
          UTF16ToUTF8(passphrase_textfield_->text());
      if (passphrase != wifi_.passphrase()) {
        wifi_.set_passphrase(passphrase);
        changed = true;
      }
    }

    if (changed)
      CrosLibrary::Get()->GetNetworkLibrary()->SaveWifiNetwork(wifi_);
  }
  return true;
}

const std::string WifiConfigView::GetSSID() const {
  std::string result;
  if (ssid_textfield_ != NULL)
    result = UTF16ToUTF8(ssid_textfield_->text());
  return result;
}

const std::string WifiConfigView::GetPassphrase() const {
  std::string result;
  if (passphrase_textfield_ != NULL)
    result = UTF16ToUTF8(passphrase_textfield_->text());
  return result;
}

void WifiConfigView::FocusFirstField() {
  if (ssid_textfield_)
    ssid_textfield_->RequestFocus();
  else if (identity_textfield_)
    identity_textfield_->RequestFocus();
  else if (passphrase_textfield_)
    passphrase_textfield_->RequestFocus();
}

// Parse 'path' to determine if the certificate is stored in a pkcs#11 device.
// flimflam recognizes the string "SETTINGS:" to specify authentication
// parameters. 'key_id=' indicates that the certificate is stored in a pkcs#11
// device. See src/third_party/flimflam/files/doc/service-api.txt.
static bool is_certificate_in_pkcs11(const std::string& path) {
  static const std::string settings_string("SETTINGS:");
  static const std::string pkcs11_key("key_id");
  if (path.find(settings_string) == 0) {
    std::string::size_type idx = path.find(pkcs11_key);
    if (idx != std::string::npos)
      idx = path.find_first_not_of(kWhitespaceASCII, idx + pkcs11_key.length());
    if (idx != std::string::npos && path[idx] == '=')
      return true;
  }
  return false;
}

void WifiConfigView::Init() {
  views::GridLayout* layout = CreatePanelGridLayout(this);
  SetLayoutManager(layout);

  int column_view_set_id = 0;
  views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
  // Label
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  // Textfield
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, kPasswordWidth);
  // Password visible button
  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, column_view_set_id);
  layout->AddView(new views::Label(l10n_util::GetString(
      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
  if (other_network_) {
    ssid_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    ssid_textfield_->SetController(this);
    layout->AddView(ssid_textfield_);
  } else {
    views::Label* label = new views::Label(ASCIIToWide(wifi_.name()));
    label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    layout->AddView(label);
  }
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Certificates stored in a pkcs11 device can not be browsed
  // and do not require a passphrase.
  bool certificate_in_pkcs11 = false;

  // Add ID and cert password if we're using 802.1x
  // XXX we're cheating and assuming 802.1x means EAP-TLS - not true
  // in general, but very common. WPA Supplicant doesn't report the
  // EAP type because it's unknown until the process begins, and we'd
  // need some kind of callback.
  if (wifi_.encrypted() && wifi_.encryption() == SECURITY_8021X) {
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_IDENTITY)));
    identity_textfield_ = new views::Textfield(
        views::Textfield::STYLE_DEFAULT);
    identity_textfield_->SetController(this);
    if (!wifi_.identity().empty())
      identity_textfield_->SetText(UTF8ToUTF16(wifi_.identity()));
    layout->AddView(identity_textfield_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT)));
    if (!wifi_.cert_path().empty()) {
      certificate_path_ = wifi_.cert_path();
      certificate_in_pkcs11 = is_certificate_in_pkcs11(certificate_path_);
    }
    if (certificate_in_pkcs11) {
      std::wstring label = l10n_util::GetString(
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_INSTALLED);
      views::Label* cert_text = new views::Label(label);
      cert_text->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      layout->AddView(cert_text);
    } else {
      std::wstring label;
      if (!certificate_path_.empty())
        label = UTF8ToWide(certificate_path_);
      else
        label = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_BUTTON;
      certificate_browse_button_ = new views::NativeButton(this, label);
      layout->AddView(certificate_browse_button_);
    }
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Add passphrase if other_network or wifi is encrypted.
  if (other_network_ || (wifi_.encrypted() && !certificate_in_pkcs11)) {
    layout->StartRow(0, column_view_set_id);
    int label_text_id;
    if (wifi_.encryption() == SECURITY_8021X)
      label_text_id =
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
    else
      label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
    layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
    passphrase_textfield_ = new views::Textfield(
        views::Textfield::STYLE_PASSWORD);
    passphrase_textfield_->SetController(this);
    if (!wifi_.passphrase().empty())
      passphrase_textfield_->SetText(UTF8ToUTF16(wifi_.passphrase()));
    layout->AddView(passphrase_textfield_);
    // Password visible button.
    passphrase_visible_button_ = new views::ImageButton(this);
    passphrase_visible_button_->SetImage(views::ImageButton::BS_NORMAL,
        ResourceBundle::GetSharedInstance().
        GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
    passphrase_visible_button_->SetImageAlignment(
        views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
    layout->AddView(passphrase_visible_button_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Autoconnect checkbox
  autoconnect_checkbox_ = new views::Checkbox(
      l10n_util::GetString(IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
  // For other network, default to autoconnect.
  bool autoconnect = other_network_ || wifi_.auto_connect();
  autoconnect_checkbox_->SetChecked(autoconnect);
  layout->StartRow(0, column_view_set_id);
  layout->AddView(autoconnect_checkbox_, 3, 1);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}

}  // namespace chromeos
<commit_msg>WifiConfigView::Init(): Fetch the localized string for the cert button, rather than using the cert button ID directly, which produces garbage.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/options/wifi_config_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/options/network_config_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/controls/button/image_button.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/standard_layout.h"
#include "views/window/window.h"

namespace chromeos {

// The width of the password field.
const int kPasswordWidth = 150;

WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork wifi)
    : parent_(parent),
      other_network_(false),
      can_login_(false),
      wifi_(wifi),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

WifiConfigView::WifiConfigView(NetworkConfigView* parent)
    : parent_(parent),
      other_network_(true),
      can_login_(false),
      ssid_textfield_(NULL),
      identity_textfield_(NULL),
      certificate_browse_button_(NULL),
      certificate_path_(),
      passphrase_textfield_(NULL),
      passphrase_visible_button_(NULL),
      autoconnect_checkbox_(NULL) {
  Init();
}

void WifiConfigView::UpdateCanLogin(void) {
  bool can_login = true;
  if (other_network_) {
    // Since the user can try to connect to a non-encrypted hidden network,
    // only enforce ssid is non-empty.
    can_login = !ssid_textfield_->text().empty();
  } else {
    // Connecting to an encrypted network
    if (passphrase_textfield_ != NULL) {
      // if the network requires a passphrase, make sure it is non empty.
      can_login &= !passphrase_textfield_->text().empty();
    }
    if (identity_textfield_ != NULL) {
      // If we have an identity field, we can login if we have a non empty
      // identity and a certificate path
      can_login &= !identity_textfield_->text().empty() &&
          !certificate_path_.empty();
    }
  }

  // Update the login button enable/disable state if can_login_ changes.
  if (can_login != can_login_) {
    can_login_ = can_login;
    parent_->GetDialogClientView()->UpdateDialogButtons();
  }
}

void WifiConfigView::ContentsChanged(views::Textfield* sender,
                                     const string16& new_contents) {
  UpdateCanLogin();
}

void WifiConfigView::ButtonPressed(views::Button* sender,
                                   const views::Event& event) {
  if (sender == passphrase_visible_button_) {
    if (passphrase_textfield_)
      passphrase_textfield_->SetPassword(!passphrase_textfield_->IsPassword());
  } else if (sender == certificate_browse_button_) {
    select_file_dialog_ = SelectFileDialog::Create(this);
    select_file_dialog_->set_browser_mode(parent_->is_browser_mode());
    select_file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE,
                                    string16(), FilePath(), NULL, 0,
                                    std::string(),
                                    parent_->is_browser_mode() ?
                                        NULL :
                                        parent_->GetNativeWindow(),
                                    NULL);
  } else {
    NOTREACHED();
  }
}

void WifiConfigView::FileSelected(const FilePath& path,
                                   int index, void* params) {
  certificate_path_ = path.value();
  if (certificate_browse_button_)
    certificate_browse_button_->SetLabel(path.BaseName().ToWStringHack());
  UpdateCanLogin();  // TODO(njw) Check if the passphrase decrypts the key.
}

bool WifiConfigView::Login() {
  std::string identity_string;
  if (identity_textfield_ != NULL) {
    identity_string = UTF16ToUTF8(identity_textfield_->text());
  }
  if (other_network_) {
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        GetSSID(), GetPassphrase(),
        identity_string, certificate_path_,
        autoconnect_checkbox_->checked());
  } else {
    Save();
    CrosLibrary::Get()->GetNetworkLibrary()->ConnectToWifiNetwork(
        wifi_, GetPassphrase(),
        identity_string, certificate_path_);
  }
  return true;
}

bool WifiConfigView::Save() {
  // Save password and auto-connect here.
  if (!other_network_) {
    bool changed = false;

    bool auto_connect = autoconnect_checkbox_->checked();
    if (auto_connect != wifi_.auto_connect()) {
      wifi_.set_auto_connect(auto_connect);
      changed = true;
    }

    if (passphrase_textfield_) {
      const std::string& passphrase =
          UTF16ToUTF8(passphrase_textfield_->text());
      if (passphrase != wifi_.passphrase()) {
        wifi_.set_passphrase(passphrase);
        changed = true;
      }
    }

    if (changed)
      CrosLibrary::Get()->GetNetworkLibrary()->SaveWifiNetwork(wifi_);
  }
  return true;
}

const std::string WifiConfigView::GetSSID() const {
  std::string result;
  if (ssid_textfield_ != NULL)
    result = UTF16ToUTF8(ssid_textfield_->text());
  return result;
}

const std::string WifiConfigView::GetPassphrase() const {
  std::string result;
  if (passphrase_textfield_ != NULL)
    result = UTF16ToUTF8(passphrase_textfield_->text());
  return result;
}

void WifiConfigView::FocusFirstField() {
  if (ssid_textfield_)
    ssid_textfield_->RequestFocus();
  else if (identity_textfield_)
    identity_textfield_->RequestFocus();
  else if (passphrase_textfield_)
    passphrase_textfield_->RequestFocus();
}

// Parse 'path' to determine if the certificate is stored in a pkcs#11 device.
// flimflam recognizes the string "SETTINGS:" to specify authentication
// parameters. 'key_id=' indicates that the certificate is stored in a pkcs#11
// device. See src/third_party/flimflam/files/doc/service-api.txt.
static bool is_certificate_in_pkcs11(const std::string& path) {
  static const std::string settings_string("SETTINGS:");
  static const std::string pkcs11_key("key_id");
  if (path.find(settings_string) == 0) {
    std::string::size_type idx = path.find(pkcs11_key);
    if (idx != std::string::npos)
      idx = path.find_first_not_of(kWhitespaceASCII, idx + pkcs11_key.length());
    if (idx != std::string::npos && path[idx] == '=')
      return true;
  }
  return false;
}

void WifiConfigView::Init() {
  views::GridLayout* layout = CreatePanelGridLayout(this);
  SetLayoutManager(layout);

  int column_view_set_id = 0;
  views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
  // Label
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  // Textfield
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, kPasswordWidth);
  // Password visible button
  column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, column_view_set_id);
  layout->AddView(new views::Label(l10n_util::GetString(
      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_NETWORK_ID)));
  if (other_network_) {
    ssid_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
    ssid_textfield_->SetController(this);
    layout->AddView(ssid_textfield_);
  } else {
    views::Label* label = new views::Label(ASCIIToWide(wifi_.name()));
    label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
    layout->AddView(label);
  }
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);

  // Certificates stored in a pkcs11 device can not be browsed
  // and do not require a passphrase.
  bool certificate_in_pkcs11 = false;

  // Add ID and cert password if we're using 802.1x
  // XXX we're cheating and assuming 802.1x means EAP-TLS - not true
  // in general, but very common. WPA Supplicant doesn't report the
  // EAP type because it's unknown until the process begins, and we'd
  // need some kind of callback.
  if (wifi_.encrypted() && wifi_.encryption() == SECURITY_8021X) {
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_IDENTITY)));
    identity_textfield_ = new views::Textfield(
        views::Textfield::STYLE_DEFAULT);
    identity_textfield_->SetController(this);
    if (!wifi_.identity().empty())
      identity_textfield_->SetText(UTF8ToUTF16(wifi_.identity()));
    layout->AddView(identity_textfield_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
    layout->StartRow(0, column_view_set_id);
    layout->AddView(new views::Label(l10n_util::GetString(
        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT)));
    if (!wifi_.cert_path().empty()) {
      certificate_path_ = wifi_.cert_path();
      certificate_in_pkcs11 = is_certificate_in_pkcs11(certificate_path_);
    }
    if (certificate_in_pkcs11) {
      std::wstring label = l10n_util::GetString(
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_INSTALLED);
      views::Label* cert_text = new views::Label(label);
      cert_text->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
      layout->AddView(cert_text);
    } else {
      std::wstring label;
      if (!certificate_path_.empty())
        label = UTF8ToWide(certificate_path_);
      else
        label = l10n_util::GetString(
            IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_BUTTON);
      certificate_browse_button_ = new views::NativeButton(this, label);
      layout->AddView(certificate_browse_button_);
    }
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Add passphrase if other_network or wifi is encrypted.
  if (other_network_ || (wifi_.encrypted() && !certificate_in_pkcs11)) {
    layout->StartRow(0, column_view_set_id);
    int label_text_id;
    if (wifi_.encryption() == SECURITY_8021X)
      label_text_id =
          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PRIVATE_KEY_PASSWORD;
    else
      label_text_id = IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE;
    layout->AddView(new views::Label(l10n_util::GetString(label_text_id)));
    passphrase_textfield_ = new views::Textfield(
        views::Textfield::STYLE_PASSWORD);
    passphrase_textfield_->SetController(this);
    if (!wifi_.passphrase().empty())
      passphrase_textfield_->SetText(UTF8ToUTF16(wifi_.passphrase()));
    layout->AddView(passphrase_textfield_);
    // Password visible button.
    passphrase_visible_button_ = new views::ImageButton(this);
    passphrase_visible_button_->SetImage(views::ImageButton::BS_NORMAL,
        ResourceBundle::GetSharedInstance().
        GetBitmapNamed(IDR_STATUSBAR_NETWORK_SECURE));
    passphrase_visible_button_->SetImageAlignment(
        views::ImageButton::ALIGN_CENTER, views::ImageButton::ALIGN_MIDDLE);
    layout->AddView(passphrase_visible_button_);
    layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  }

  // Autoconnect checkbox
  autoconnect_checkbox_ = new views::Checkbox(
      l10n_util::GetString(IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_AUTO_CONNECT));
  // For other network, default to autoconnect.
  bool autoconnect = other_network_ || wifi_.auto_connect();
  autoconnect_checkbox_->SetChecked(autoconnect);
  layout->StartRow(0, column_view_set_id);
  layout->AddView(autoconnect_checkbox_, 3, 1);
  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
}

}  // namespace chromeos
<|endoftext|>


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

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  explicit BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kConsoleTestPage[] = L"files/devtools/console_test_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";
const wchar_t kEvalTestPage[] = L"files/devtools/eval_test_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kPauseOnExceptionTestPage[] =
    L"files/devtools/pause_on_exception.html";
const wchar_t kPauseWhenLoadingDevTools[] =
    L"files/devtools/pause_when_loading_devtools.html";
const wchar_t kPauseWhenScriptIsRunning[] =
    L"files/devtools/pause_when_script_is_running.html";
const wchar_t kResourceContentLengthTestPage[] = L"files/devtools/image.html";
const wchar_t kResourceTestPage[] = L"files/devtools/resource_test_page.html";
const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kSyntaxErrorTestPage[] =
    L"files/devtools/script_syntax_error.html";
const wchar_t kDebuggerStepTestPage[] =
    L"files/devtools/debugger_step.html";
const wchar_t kDebuggerClosurePage[] =
    L"files/devtools/debugger_closure.html";
const wchar_t kDebuggerIntrinsicPropertiesPage[] =
    L"files/devtools/debugger_intrinsic_properties.html";
const wchar_t kCompletionOnPause[] =
    L"files/devtools/completion_on_pause.html";
const wchar_t kPageWithContentScript[] =
    L"files/devtools/page_with_content_script.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    inspected_rvh_ = GetInspectedTab()->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  TabContents* GetInspectedTab() {
    return browser()->GetTabContentsAt(0);
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

class CancelableQuitTask : public Task {
 public:
  explicit CancelableQuitTask(const std::string& timeout_message)
      : timeout_message_(timeout_message),
        cancelled_(false) {
  }

  void cancel() {
    cancelled_ = true;
  }

  virtual void Run() {
    if (cancelled_) {
      return;
    }
    FAIL() << timeout_message_;
    MessageLoop::current()->Quit();
  }

 private:
  std::string timeout_message_;
  bool cancelled_;
};

// Base class for DevTools tests that test devtools functionality for
// extensions and content scripts.
class DevToolsExtensionDebugTest : public DevToolsSanityTest,
                                   public NotificationObserver {
 public:
  DevToolsExtensionDebugTest() : DevToolsSanityTest() {
    PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
  }

 protected:
  // Load an extention from test\data\devtools\extensions\<extension_name>
  void LoadExtension(const char* extension_name) {
    FilePath path = test_extensions_dir_.AppendASCII(extension_name);
    ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
  }

 private:
  bool LoadExtensionFromPath(const FilePath& path) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    size_t num_before = service->extensions()->size();
    {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::EXTENSION_LOADED,
                    NotificationService::AllSources());
      CancelableQuitTask* delayed_quit =
          new CancelableQuitTask("Extension load timed out.");
      MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
          4*1000);
      service->LoadExtension(path);
      ui_test_utils::RunMessageLoop();
      delayed_quit->cancel();
    }
    size_t num_after = service->extensions()->size();
    if (num_after != (num_before + 1))
      return false;

    return WaitForExtensionHostsToLoad();
  }

  bool WaitForExtensionHostsToLoad() {
    // Wait for all the extension hosts that exist to finish loading.
    // NOTE: This assumes that the extension host list is not changing while
    // this method is running.

    NotificationRegistrar registrar;
    registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
                  NotificationService::AllSources());
    CancelableQuitTask* delayed_quit =
        new CancelableQuitTask("Extension host load timed out.");
    MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
        4*1000);

    ExtensionProcessManager* manager =
          browser()->profile()->GetExtensionProcessManager();
    for (ExtensionProcessManager::const_iterator iter = manager->begin();
         iter != manager->end();) {
      if ((*iter)->did_stop_loading())
        ++iter;
      else
        ui_test_utils::RunMessageLoop();
    }

    delayed_quit->cancel();
    return true;
  }

  void Observe(NotificationType type,
               const NotificationSource& source,
               const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::EXTENSION_LOADED:
      case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
        MessageLoopForUI::current()->Quit();
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  FilePath test_extensions_dir_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests resources have correct sizes.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceContentLength) {
  RunTest("testResourceContentLength", kResourceContentLengthTestPage);
}

// Tests resource headers.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceHeaders) {
  RunTest("testResourceHeaders", kResourceTestPage);
}

// Tests cached resource mime type.
// @see http://crbug.com/27364
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCachedResourceMimeType) {
  RunTest("testCachedResourceMimeType", kResourceTestPage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts tab is populated with inspected scripts even if it
// hadn't been shown by the moment inspected paged refreshed.
// @see http://crbug.com/26312
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
  // Reset inspector settings to defaults to ensure that Elements will be
  // current panel when DevTools window is open.
  GetInspectedTab()->render_view_host()->delegate()->UpdateInspectorSettings(
      WebPreferences().inspector_settings);
  RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
          kDebuggerTestPage);
}

// Tests that a content script is in the scripts list.
// This test is disabled, see bug 28961.
IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,
                       DISABLED_TestContentScriptIsPresent) {
  LoadExtension("simple_content_script");
  RunTest("testContentScriptIsPresent", kPageWithContentScript);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests set breakpoint.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSetBreakpoint) {
  RunTest("testSetBreakpoint", kDebuggerTestPage);
}

// Tests pause on exception.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseOnException) {
  RunTest("testPauseOnException", kPauseOnExceptionTestPage);
}

// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
  RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
}

// Tests that pressing 'Pause' will pause script execution if the script
// is already running.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenScriptIsRunning) {
  RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}

// Tests eval on call frame.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalOnCallFrame) {
  RunTest("testEvalOnCallFrame", kDebuggerTestPage);
}

// Tests step over functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOver) {
  RunTest("testStepOver", kDebuggerStepTestPage);
}

// Tests step out functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOut) {
  RunTest("testStepOut", kDebuggerStepTestPage);
}

// Tests step in functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepIn) {
  RunTest("testStepIn", kDebuggerStepTestPage);
}

// Tests that scope can be expanded and contains expected variables.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestExpandScope) {
  RunTest("testExpandScope", kDebuggerClosurePage);
}

// Tests that intrinsic properties(__proto__, prototype, constructor) are
// present.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDebugIntrinsicProperties) {
  RunTest("testDebugIntrinsicProperties", kDebuggerIntrinsicPropertiesPage);
}

// Tests that execution continues automatically when there is a syntax error in
// script and DevTools are open.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestAutoContinueOnSyntaxError) {
  RunTest("testAutoContinueOnSyntaxError", kSyntaxErrorTestPage);
}

IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

// Tests console eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleEval) {
  RunTest("testConsoleEval", kConsoleTestPage);
}

// Tests console log.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleLog) {
  RunTest("testConsoleLog", kConsoleTestPage);
}

// Tests eval global values.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalGlobal) {
  RunTest("testEvalGlobal", kEvalTestPage);
}

// Test that Storage panel can be shown.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowStoragePanel) {
  RunTest("testShowStoragePanel", kDebuggerTestPage);
}

}  // namespace
<commit_msg>DevTools: temporarily diable DevToolsSanityTest.TestPauseWhenScriptIsRunning which fails on Linux<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

namespace {

// Used to block until a dev tools client window's browser is closed.
class BrowserClosedObserver : public NotificationObserver {
 public:
  explicit BrowserClosedObserver(Browser* browser) {
    registrar_.Add(this, NotificationType::BROWSER_CLOSED,
                   Source<Browser>(browser));
    ui_test_utils::RunMessageLoop();
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    MessageLoopForUI::current()->Quit();
  }

 private:
  NotificationRegistrar registrar_;
  DISALLOW_COPY_AND_ASSIGN(BrowserClosedObserver);
};

// The delay waited in some cases where we don't have a notifications for an
// action we take.
const int kActionDelayMs = 500;

const wchar_t kConsoleTestPage[] = L"files/devtools/console_test_page.html";
const wchar_t kDebuggerTestPage[] = L"files/devtools/debugger_test_page.html";
const wchar_t kEvalTestPage[] = L"files/devtools/eval_test_page.html";
const wchar_t kJsPage[] = L"files/devtools/js_page.html";
const wchar_t kPauseOnExceptionTestPage[] =
    L"files/devtools/pause_on_exception.html";
const wchar_t kPauseWhenLoadingDevTools[] =
    L"files/devtools/pause_when_loading_devtools.html";
const wchar_t kPauseWhenScriptIsRunning[] =
    L"files/devtools/pause_when_script_is_running.html";
const wchar_t kResourceContentLengthTestPage[] = L"files/devtools/image.html";
const wchar_t kResourceTestPage[] = L"files/devtools/resource_test_page.html";
const wchar_t kSimplePage[] = L"files/devtools/simple_page.html";
const wchar_t kSyntaxErrorTestPage[] =
    L"files/devtools/script_syntax_error.html";
const wchar_t kDebuggerStepTestPage[] =
    L"files/devtools/debugger_step.html";
const wchar_t kDebuggerClosurePage[] =
    L"files/devtools/debugger_closure.html";
const wchar_t kDebuggerIntrinsicPropertiesPage[] =
    L"files/devtools/debugger_intrinsic_properties.html";
const wchar_t kCompletionOnPause[] =
    L"files/devtools/completion_on_pause.html";
const wchar_t kPageWithContentScript[] =
    L"files/devtools/page_with_content_script.html";

class DevToolsSanityTest : public InProcessBrowserTest {
 public:
  DevToolsSanityTest() {
    set_show_window(true);
    EnableDOMAutomation();
  }

 protected:
  void RunTest(const std::string& test_name, const std::wstring& test_page) {
    OpenDevToolsWindow(test_page);
    std::string result;

    // At first check that JavaScript part of the front-end is loaded by
    // checking that global variable uiTests exists(it's created after all js
    // files have been loaded) and has runTest method.
    ASSERT_TRUE(
        ui_test_utils::ExecuteJavaScriptAndExtractString(
            client_contents_->render_view_host(),
            L"",
            L"window.domAutomationController.send("
            L"'' + (window.uiTests && (typeof uiTests.runTest)));",
            &result));

    if (result == "function") {
      ASSERT_TRUE(
          ui_test_utils::ExecuteJavaScriptAndExtractString(
              client_contents_->render_view_host(),
              L"",
              UTF8ToWide(StringPrintf("uiTests.runTest('%s')",
                                      test_name.c_str())),
              &result));
      EXPECT_EQ("[OK]", result);
    } else {
      FAIL() << "DevTools front-end is broken.";
    }
    CloseDevToolsWindow();
  }

  void OpenDevToolsWindow(const std::wstring& test_page) {
    HTTPTestServer* server = StartHTTPServer();
    GURL url = server->TestServerPageW(test_page);
    ui_test_utils::NavigateToURL(browser(), url);

    inspected_rvh_ = GetInspectedTab()->render_view_host();
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    devtools_manager->OpenDevToolsWindow(inspected_rvh_);

    DevToolsClientHost* client_host =
        devtools_manager->GetDevToolsClientHostFor(inspected_rvh_);
    window_ = client_host->AsDevToolsWindow();
    RenderViewHost* client_rvh = window_->GetRenderViewHost();
    client_contents_ = client_rvh->delegate()->GetAsTabContents();
    ui_test_utils::WaitForNavigation(&client_contents_->controller());
  }

  TabContents* GetInspectedTab() {
    return browser()->GetTabContentsAt(0);
  }

  void CloseDevToolsWindow() {
    DevToolsManager* devtools_manager = DevToolsManager::GetInstance();
    // UnregisterDevToolsClientHostFor may destroy window_ so store the browser
    // first.
    Browser* browser = window_->browser();
    devtools_manager->UnregisterDevToolsClientHostFor(inspected_rvh_);
    BrowserClosedObserver close_observer(browser);
  }

  TabContents* client_contents_;
  DevToolsWindow* window_;
  RenderViewHost* inspected_rvh_;
};

class CancelableQuitTask : public Task {
 public:
  explicit CancelableQuitTask(const std::string& timeout_message)
      : timeout_message_(timeout_message),
        cancelled_(false) {
  }

  void cancel() {
    cancelled_ = true;
  }

  virtual void Run() {
    if (cancelled_) {
      return;
    }
    FAIL() << timeout_message_;
    MessageLoop::current()->Quit();
  }

 private:
  std::string timeout_message_;
  bool cancelled_;
};

// Base class for DevTools tests that test devtools functionality for
// extensions and content scripts.
class DevToolsExtensionDebugTest : public DevToolsSanityTest,
                                   public NotificationObserver {
 public:
  DevToolsExtensionDebugTest() : DevToolsSanityTest() {
    PathService::Get(chrome::DIR_TEST_DATA, &test_extensions_dir_);
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("devtools");
    test_extensions_dir_ = test_extensions_dir_.AppendASCII("extensions");
  }

 protected:
  // Load an extention from test\data\devtools\extensions\<extension_name>
  void LoadExtension(const char* extension_name) {
    FilePath path = test_extensions_dir_.AppendASCII(extension_name);
    ASSERT_TRUE(LoadExtensionFromPath(path)) << "Failed to load extension.";
  }

 private:
  bool LoadExtensionFromPath(const FilePath& path) {
    ExtensionsService* service = browser()->profile()->GetExtensionsService();
    size_t num_before = service->extensions()->size();
    {
      NotificationRegistrar registrar;
      registrar.Add(this, NotificationType::EXTENSION_LOADED,
                    NotificationService::AllSources());
      CancelableQuitTask* delayed_quit =
          new CancelableQuitTask("Extension load timed out.");
      MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
          4*1000);
      service->LoadExtension(path);
      ui_test_utils::RunMessageLoop();
      delayed_quit->cancel();
    }
    size_t num_after = service->extensions()->size();
    if (num_after != (num_before + 1))
      return false;

    return WaitForExtensionHostsToLoad();
  }

  bool WaitForExtensionHostsToLoad() {
    // Wait for all the extension hosts that exist to finish loading.
    // NOTE: This assumes that the extension host list is not changing while
    // this method is running.

    NotificationRegistrar registrar;
    registrar.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
                  NotificationService::AllSources());
    CancelableQuitTask* delayed_quit =
        new CancelableQuitTask("Extension host load timed out.");
    MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
        4*1000);

    ExtensionProcessManager* manager =
          browser()->profile()->GetExtensionProcessManager();
    for (ExtensionProcessManager::const_iterator iter = manager->begin();
         iter != manager->end();) {
      if ((*iter)->did_stop_loading())
        ++iter;
      else
        ui_test_utils::RunMessageLoop();
    }

    delayed_quit->cancel();
    return true;
  }

  void Observe(NotificationType type,
               const NotificationSource& source,
               const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::EXTENSION_LOADED:
      case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
        MessageLoopForUI::current()->Quit();
        break;
      default:
        NOTREACHED();
        break;
    }
  }

  FilePath test_extensions_dir_;
};

// WebInspector opens.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestHostIsPresent) {
  RunTest("testHostIsPresent", kSimplePage);
}

// Tests elements panel basics.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestElementsTreeRoot) {
  RunTest("testElementsTreeRoot", kSimplePage);
}

// Tests main resource load.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestMainResource) {
  RunTest("testMainResource", kSimplePage);
}

// Tests resources panel enabling.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEnableResourcesTab) {
  RunTest("testEnableResourcesTab", kSimplePage);
}

// Tests resources have correct sizes.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceContentLength) {
  RunTest("testResourceContentLength", kResourceContentLengthTestPage);
}

// Tests resource headers.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestResourceHeaders) {
  RunTest("testResourceHeaders", kResourceTestPage);
}

// Tests cached resource mime type.
// @see http://crbug.com/27364
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCachedResourceMimeType) {
  RunTest("testCachedResourceMimeType", kResourceTestPage);
}

// Tests profiler panel.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestProfilerTab) {
  RunTest("testProfilerTab", kJsPage);
}

// Tests scripts panel showing.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowScriptsTab) {
  RunTest("testShowScriptsTab", kDebuggerTestPage);
}

// Tests that scripts tab is populated with inspected scripts even if it
// hadn't been shown by the moment inspected paged refreshed.
// @see http://crbug.com/26312
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestScriptsTabIsPopulatedOnInspectedPageRefresh) {
  // Reset inspector settings to defaults to ensure that Elements will be
  // current panel when DevTools window is open.
  GetInspectedTab()->render_view_host()->delegate()->UpdateInspectorSettings(
      WebPreferences().inspector_settings);
  RunTest("testScriptsTabIsPopulatedOnInspectedPageRefresh",
          kDebuggerTestPage);
}

// Tests that a content script is in the scripts list.
// This test is disabled, see bug 28961.
IN_PROC_BROWSER_TEST_F(DevToolsExtensionDebugTest,
                       DISABLED_TestContentScriptIsPresent) {
  LoadExtension("simple_content_script");
  RunTest("testContentScriptIsPresent", kPageWithContentScript);
}

// Tests that scripts are not duplicated after Scripts Panel switch.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest,
                       TestNoScriptDuplicatesOnPanelSwitch) {
  RunTest("testNoScriptDuplicatesOnPanelSwitch", kDebuggerTestPage);
}

// Tests set breakpoint.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestSetBreakpoint) {
  RunTest("testSetBreakpoint", kDebuggerTestPage);
}

// Tests pause on exception.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseOnException) {
  RunTest("testPauseOnException", kPauseOnExceptionTestPage);
}

// Tests that debugger works correctly if pause event occurs when DevTools
// frontend is being loaded.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestPauseWhenLoadingDevTools) {
  RunTest("testPauseWhenLoadingDevTools", kPauseWhenLoadingDevTools);
}

// Tests that pressing 'Pause' will pause script execution if the script
// is already running.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseWhenScriptIsRunning) {
  RunTest("testPauseWhenScriptIsRunning", kPauseWhenScriptIsRunning);
}

// Tests eval on call frame.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalOnCallFrame) {
  RunTest("testEvalOnCallFrame", kDebuggerTestPage);
}

// Tests step over functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOver) {
  RunTest("testStepOver", kDebuggerStepTestPage);
}

// Tests step out functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepOut) {
  RunTest("testStepOut", kDebuggerStepTestPage);
}

// Tests step in functionality in the debugger.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestStepIn) {
  RunTest("testStepIn", kDebuggerStepTestPage);
}

// Tests that scope can be expanded and contains expected variables.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestExpandScope) {
  RunTest("testExpandScope", kDebuggerClosurePage);
}

// Tests that intrinsic properties(__proto__, prototype, constructor) are
// present.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestDebugIntrinsicProperties) {
  RunTest("testDebugIntrinsicProperties", kDebuggerIntrinsicPropertiesPage);
}

// Tests that execution continues automatically when there is a syntax error in
// script and DevTools are open.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestAutoContinueOnSyntaxError) {
  RunTest("testAutoContinueOnSyntaxError", kSyntaxErrorTestPage);
}

IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestCompletionOnPause) {
  RunTest("testCompletionOnPause", kCompletionOnPause);
}

// Tests that 'Pause' button works for eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, DISABLED_TestPauseInEval) {
  RunTest("testPauseInEval", kDebuggerTestPage);
}

// Tests console eval.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleEval) {
  RunTest("testConsoleEval", kConsoleTestPage);
}

// Tests console log.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestConsoleLog) {
  RunTest("testConsoleLog", kConsoleTestPage);
}

// Tests eval global values.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestEvalGlobal) {
  RunTest("testEvalGlobal", kEvalTestPage);
}

// Test that Storage panel can be shown.
IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, TestShowStoragePanel) {
  RunTest("testShowStoragePanel", kDebuggerTestPage);
}

}  // namespace
<|endoftext|>