<commit_before>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

#include "arch/utility.hh"
#include "arch/faults.hh"
#include "base/cprintf.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/range.hh"
#include "base/stats/events.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "cpu/profile.hh"
#include "cpu/simple/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "mem/packet.hh"
#include "sim/builder.hh"
#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
#include "sim/system.hh"

#if FULL_SYSTEM
#include "arch/kernel_stats.hh"
#include "arch/stacktrace.hh"
#include "arch/tlb.hh"
#include "arch/vtophys.hh"
#include "base/remote_gdb.hh"
#else // !FULL_SYSTEM
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM

using namespace std;
using namespace TheISA;

BaseSimpleCPU::BaseSimpleCPU(Params *p)
    : BaseCPU(p), thread(NULL), predecoder(NULL)
{
#if FULL_SYSTEM
    thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
#else
    thread = new SimpleThread(this, /* thread_num */ 0, p->process,
            /* asid */ 0);
#endif // !FULL_SYSTEM

    thread->setStatus(ThreadContext::Suspended);

    tc = thread->getTC();

    numInst = 0;
    startNumInst = 0;
    numLoad = 0;
    startNumLoad = 0;
    lastIcacheStall = 0;
    lastDcacheStall = 0;

    threadContexts.push_back(tc);
}

BaseSimpleCPU::~BaseSimpleCPU()
{
}

void
BaseSimpleCPU::deallocateContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::haltContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::regStats()
{
    using namespace Stats;

    BaseCPU::regStats();

    numInsts
        .name(name() + ".num_insts")
        .desc("Number of instructions executed")
        ;

    numMemRefs
        .name(name() + ".num_refs")
        .desc("Number of memory references")
        ;

    notIdleFraction
        .name(name() + ".not_idle_fraction")
        .desc("Percentage of non-idle cycles")
        ;

    idleFraction
        .name(name() + ".idle_fraction")
        .desc("Percentage of idle cycles")
        ;

    icacheStallCycles
        .name(name() + ".icache_stall_cycles")
        .desc("ICache total stall cycles")
        .prereq(icacheStallCycles)
        ;

    dcacheStallCycles
        .name(name() + ".dcache_stall_cycles")
        .desc("DCache total stall cycles")
        .prereq(dcacheStallCycles)
        ;

    icacheRetryCycles
        .name(name() + ".icache_retry_cycles")
        .desc("ICache total retry cycles")
        .prereq(icacheRetryCycles)
        ;

    dcacheRetryCycles
        .name(name() + ".dcache_retry_cycles")
        .desc("DCache total retry cycles")
        .prereq(dcacheRetryCycles)
        ;

    idleFraction = constant(1.0) - notIdleFraction;
}

void
BaseSimpleCPU::resetStats()
{
//    startNumInst = numInst;
    // notIdleFraction = (_status != Idle);
}

void
BaseSimpleCPU::serialize(ostream &os)
{
    BaseCPU::serialize(os);
//    SERIALIZE_SCALAR(inst);
    nameOut(os, csprintf("%s.xc.0", name()));
    thread->serialize(os);
}

void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
    BaseCPU::unserialize(cp, section);
//    UNSERIALIZE_SCALAR(inst);
    thread->unserialize(cp, csprintf("%s.xc.0", section));
}

void
change_thread_state(int thread_number, int activate, int priority)
{
}

Fault
BaseSimpleCPU::copySrcTranslate(Addr src)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    int offset = src & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (src & PageMask) != ((src + blk_size) & PageMask) &&
        (src >> 40) != 0xfffffc) {
        warn("Copied block source spans pages %x.", src);
        no_warn = false;
    }

    memReq->reset(src & ~(blk_size - 1), blk_size);

    // translate to physical address
    Fault fault = thread->translateDataReadReq(req);

    if (fault == NoFault) {
        thread->copySrcAddr = src;
        thread->copySrcPhysAddr = memReq->paddr + offset;
    } else {
        assert(!fault->isAlignmentFault());

        thread->copySrcAddr = 0;
        thread->copySrcPhysAddr = 0;
    }
    return fault;
#else
    return NoFault;
#endif
}

Fault
BaseSimpleCPU::copy(Addr dest)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    uint8_t data[blk_size];
    //assert(thread->copySrcAddr);
    int offset = dest & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
        (dest >> 40) != 0xfffffc) {
        no_warn = false;
        warn("Copied block destination spans pages %x. ", dest);
    }

    memReq->reset(dest & ~(blk_size -1), blk_size);
    // translate to physical address
    Fault fault = thread->translateDataWriteReq(req);

    if (fault == NoFault) {
        Addr dest_addr = memReq->paddr + offset;
        // Need to read straight from memory since we have more than 8 bytes.
        memReq->paddr = thread->copySrcPhysAddr;
        thread->mem->read(memReq, data);
        memReq->paddr = dest_addr;
        thread->mem->write(memReq, data);
        if (dcacheInterface) {
            memReq->cmd = Copy;
            memReq->completionEvent = NULL;
            memReq->paddr = thread->copySrcPhysAddr;
            memReq->dest = dest_addr;
            memReq->size = 64;
            memReq->time = curTick;
            memReq->flags &= ~INST_READ;
            dcacheInterface->access(memReq);
        }
    }
    else
        assert(!fault->isAlignmentFault());

    return fault;
#else
    panic("copy not implemented");
    return NoFault;
#endif
}

#if FULL_SYSTEM
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
    return vtophys(tc, addr);
}
#endif // FULL_SYSTEM

#if FULL_SYSTEM
void
BaseSimpleCPU::post_interrupt(int int_num, int index)
{
    BaseCPU::post_interrupt(int_num, index);

    if (thread->status() == ThreadContext::Suspended) {
                DPRINTF(Quiesce,"Suspended Processor awoke\n");
        thread->activate();
    }
}
#endif // FULL_SYSTEM

void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
    if (check_interrupts(tc)) {
        Fault interrupt = interrupts.getInterrupt(tc);

        if (interrupt != NoFault) {
            interrupts.updateIntrInfo(tc);
            interrupt->invoke(tc);
        }
    }
#endif
}

Fault
BaseSimpleCPU::setupFetchRequest(Request *req)
{
    // set up memory request for instruction fetch
#if ISA_HAS_DELAY_SLOT
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(),
            thread->readNextPC(),thread->readNextNPC());
#else
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(),
            thread->readNextPC());
#endif

    req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst), 0,
            thread->readPC());

    Fault fault = thread->translateInstReq(req);

    return fault;
}

void
BaseSimpleCPU::preExecute()
{
    // maintain $r0 semantics
    thread->setIntReg(ZeroReg, 0);
#if THE_ISA == ALPHA_ISA
    thread->setFloatReg(ZeroReg, 0.0);
#endif // ALPHA_ISA

    // keep an instruction count
    numInst++;
    numInsts++;

    thread->funcExeInst++;

    // check for instruction-count-based events
    comInstEventQueue[0]->serviceEvents(numInst);

    // decode the instruction
    inst = gtoh(inst);
    //If we're not in the middle of a macro instruction
    if (!curMacroStaticInst) {
        StaticInstPtr instPtr = NULL;

        //Predecode, ie bundle up an ExtMachInst
        //This should go away once the constructor can be set up properly
        predecoder.setTC(thread->getTC());
        //If more fetch data is needed, pass it in.
        if(predecoder.needMoreBytes())
            predecoder.moreBytes(thread->readPC(), 0, inst);
        else
            predecoder.process();
        //If an instruction is ready, decode it
        if (predecoder.extMachInstReady())
            instPtr = StaticInst::decode(predecoder.getExtMachInst());

        //If we decoded an instruction and it's microcoded, start pulling
        //out micro ops
        if (instPtr && instPtr->isMacroOp()) {
            curMacroStaticInst = instPtr;
            curStaticInst = curMacroStaticInst->
                fetchMicroOp(thread->readMicroPC());
        } else {
            curStaticInst = instPtr;
        }
    } else {
        //Read the next micro op from the macro op
        curStaticInst = curMacroStaticInst->
            fetchMicroOp(thread->readMicroPC());
    }

    //If we decoded an instruction this "tick", record information about it.
    if(curStaticInst)
    {
        traceData = Trace::getInstRecord(curTick, tc, curStaticInst,
                                         thread->readPC());

        DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
                curStaticInst->getName(), curStaticInst->machInst);

#if FULL_SYSTEM
        thread->setInst(inst);
#endif // FULL_SYSTEM
    }
}

void
BaseSimpleCPU::postExecute()
{
#if FULL_SYSTEM
    if (thread->profile) {
        bool usermode = TheISA::inUserMode(tc);
        thread->profilePC = usermode ? 1 : thread->readPC();
        StaticInstPtr si(inst);
        ProfileNode *node = thread->profile->consume(tc, si);
        if (node)
            thread->profileNode = node;
    }
#endif

    if (curStaticInst->isMemRef()) {
        numMemRefs++;
    }

    if (curStaticInst->isLoad()) {
        ++numLoad;
        comLoadEventQueue[0]->serviceEvents(numLoad);
    }

    traceFunctions(thread->readPC());

    if (traceData) {
        traceData->dump();
        delete traceData;
        traceData = NULL;
    }
}

void
BaseSimpleCPU::advancePC(Fault fault)
{
    if (fault != NoFault) {
        curMacroStaticInst = StaticInst::nullStaticInstPtr;
        fault->invoke(tc);
        thread->setMicroPC(0);
        thread->setNextMicroPC(1);
    } else if (predecoder.needMoreBytes()) {
        //If we're at the last micro op for this instruction
        if (curStaticInst && curStaticInst->isLastMicroOp()) {
            //We should be working with a macro op
            assert(curMacroStaticInst);
            //Close out this macro op, and clean up the
            //microcode state
            curMacroStaticInst = StaticInst::nullStaticInstPtr;
            thread->setMicroPC(0);
            thread->setNextMicroPC(1);
        }
        //If we're still in a macro op
        if (curMacroStaticInst) {
            //Advance the micro pc
            thread->setMicroPC(thread->readNextMicroPC());
            //Advance the "next" micro pc. Note that there are no delay
            //slots, and micro ops are "word" addressed.
            thread->setNextMicroPC(thread->readNextMicroPC() + 1);
        } else {
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextNPC());
            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
            assert(thread->readNextPC() != thread->readNextNPC());
        }
    }

#if FULL_SYSTEM
    Addr oldpc;
    do {
        oldpc = thread->readPC();
        system->pcEventQueue.service(tc);
    } while (oldpc != thread->readPC());
#endif
}

<commit_msg>Use a computed mask to mask out the fetch address and not a hard coded one.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

#include "arch/utility.hh"
#include "arch/faults.hh"
#include "base/cprintf.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/pollevent.hh"
#include "base/range.hh"
#include "base/stats/events.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "cpu/profile.hh"
#include "cpu/simple/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "mem/packet.hh"
#include "sim/builder.hh"
#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
#include "sim/system.hh"

#if FULL_SYSTEM
#include "arch/kernel_stats.hh"
#include "arch/stacktrace.hh"
#include "arch/tlb.hh"
#include "arch/vtophys.hh"
#include "base/remote_gdb.hh"
#else // !FULL_SYSTEM
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM

using namespace std;
using namespace TheISA;

BaseSimpleCPU::BaseSimpleCPU(Params *p)
    : BaseCPU(p), thread(NULL), predecoder(NULL)
{
#if FULL_SYSTEM
    thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
#else
    thread = new SimpleThread(this, /* thread_num */ 0, p->process,
            /* asid */ 0);
#endif // !FULL_SYSTEM

    thread->setStatus(ThreadContext::Suspended);

    tc = thread->getTC();

    numInst = 0;
    startNumInst = 0;
    numLoad = 0;
    startNumLoad = 0;
    lastIcacheStall = 0;
    lastDcacheStall = 0;

    threadContexts.push_back(tc);
}

BaseSimpleCPU::~BaseSimpleCPU()
{
}

void
BaseSimpleCPU::deallocateContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::haltContext(int thread_num)
{
    // for now, these are equivalent
    suspendContext(thread_num);
}

void
BaseSimpleCPU::regStats()
{
    using namespace Stats;

    BaseCPU::regStats();

    numInsts
        .name(name() + ".num_insts")
        .desc("Number of instructions executed")
        ;

    numMemRefs
        .name(name() + ".num_refs")
        .desc("Number of memory references")
        ;

    notIdleFraction
        .name(name() + ".not_idle_fraction")
        .desc("Percentage of non-idle cycles")
        ;

    idleFraction
        .name(name() + ".idle_fraction")
        .desc("Percentage of idle cycles")
        ;

    icacheStallCycles
        .name(name() + ".icache_stall_cycles")
        .desc("ICache total stall cycles")
        .prereq(icacheStallCycles)
        ;

    dcacheStallCycles
        .name(name() + ".dcache_stall_cycles")
        .desc("DCache total stall cycles")
        .prereq(dcacheStallCycles)
        ;

    icacheRetryCycles
        .name(name() + ".icache_retry_cycles")
        .desc("ICache total retry cycles")
        .prereq(icacheRetryCycles)
        ;

    dcacheRetryCycles
        .name(name() + ".dcache_retry_cycles")
        .desc("DCache total retry cycles")
        .prereq(dcacheRetryCycles)
        ;

    idleFraction = constant(1.0) - notIdleFraction;
}

void
BaseSimpleCPU::resetStats()
{
//    startNumInst = numInst;
    // notIdleFraction = (_status != Idle);
}

void
BaseSimpleCPU::serialize(ostream &os)
{
    BaseCPU::serialize(os);
//    SERIALIZE_SCALAR(inst);
    nameOut(os, csprintf("%s.xc.0", name()));
    thread->serialize(os);
}

void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
    BaseCPU::unserialize(cp, section);
//    UNSERIALIZE_SCALAR(inst);
    thread->unserialize(cp, csprintf("%s.xc.0", section));
}

void
change_thread_state(int thread_number, int activate, int priority)
{
}

Fault
BaseSimpleCPU::copySrcTranslate(Addr src)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    int offset = src & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (src & PageMask) != ((src + blk_size) & PageMask) &&
        (src >> 40) != 0xfffffc) {
        warn("Copied block source spans pages %x.", src);
        no_warn = false;
    }

    memReq->reset(src & ~(blk_size - 1), blk_size);

    // translate to physical address
    Fault fault = thread->translateDataReadReq(req);

    if (fault == NoFault) {
        thread->copySrcAddr = src;
        thread->copySrcPhysAddr = memReq->paddr + offset;
    } else {
        assert(!fault->isAlignmentFault());

        thread->copySrcAddr = 0;
        thread->copySrcPhysAddr = 0;
    }
    return fault;
#else
    return NoFault;
#endif
}

Fault
BaseSimpleCPU::copy(Addr dest)
{
#if 0
    static bool no_warn = true;
    int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
    // Only support block sizes of 64 atm.
    assert(blk_size == 64);
    uint8_t data[blk_size];
    //assert(thread->copySrcAddr);
    int offset = dest & (blk_size - 1);

    // Make sure block doesn't span page
    if (no_warn &&
        (dest & PageMask) != ((dest + blk_size) & PageMask) &&
        (dest >> 40) != 0xfffffc) {
        no_warn = false;
        warn("Copied block destination spans pages %x. ", dest);
    }

    memReq->reset(dest & ~(blk_size -1), blk_size);
    // translate to physical address
    Fault fault = thread->translateDataWriteReq(req);

    if (fault == NoFault) {
        Addr dest_addr = memReq->paddr + offset;
        // Need to read straight from memory since we have more than 8 bytes.
        memReq->paddr = thread->copySrcPhysAddr;
        thread->mem->read(memReq, data);
        memReq->paddr = dest_addr;
        thread->mem->write(memReq, data);
        if (dcacheInterface) {
            memReq->cmd = Copy;
            memReq->completionEvent = NULL;
            memReq->paddr = thread->copySrcPhysAddr;
            memReq->dest = dest_addr;
            memReq->size = 64;
            memReq->time = curTick;
            memReq->flags &= ~INST_READ;
            dcacheInterface->access(memReq);
        }
    }
    else
        assert(!fault->isAlignmentFault());

    return fault;
#else
    panic("copy not implemented");
    return NoFault;
#endif
}

#if FULL_SYSTEM
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
    return vtophys(tc, addr);
}
#endif // FULL_SYSTEM

#if FULL_SYSTEM
void
BaseSimpleCPU::post_interrupt(int int_num, int index)
{
    BaseCPU::post_interrupt(int_num, index);

    if (thread->status() == ThreadContext::Suspended) {
                DPRINTF(Quiesce,"Suspended Processor awoke\n");
        thread->activate();
    }
}
#endif // FULL_SYSTEM

void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
    if (check_interrupts(tc)) {
        Fault interrupt = interrupts.getInterrupt(tc);

        if (interrupt != NoFault) {
            interrupts.updateIntrInfo(tc);
            interrupt->invoke(tc);
        }
    }
#endif
}

Fault
BaseSimpleCPU::setupFetchRequest(Request *req)
{
    // set up memory request for instruction fetch
#if ISA_HAS_DELAY_SLOT
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(),
            thread->readNextPC(),thread->readNextNPC());
#else
    DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(),
            thread->readNextPC());
#endif

    // This will generate a mask which aligns the pc on MachInst size
    // boundaries. It won't work for non-power-of-two sized MachInsts, but
    // it will work better than a hard coded mask.
    const Addr PCMask = ~(sizeof(MachInst) - 1);
    req->setVirt(0, thread->readPC() & PCMask, sizeof(MachInst), 0,
            thread->readPC());

    Fault fault = thread->translateInstReq(req);

    return fault;
}

void
BaseSimpleCPU::preExecute()
{
    // maintain $r0 semantics
    thread->setIntReg(ZeroReg, 0);
#if THE_ISA == ALPHA_ISA
    thread->setFloatReg(ZeroReg, 0.0);
#endif // ALPHA_ISA

    // keep an instruction count
    numInst++;
    numInsts++;

    thread->funcExeInst++;

    // check for instruction-count-based events
    comInstEventQueue[0]->serviceEvents(numInst);

    // decode the instruction
    inst = gtoh(inst);
    //If we're not in the middle of a macro instruction
    if (!curMacroStaticInst) {
        StaticInstPtr instPtr = NULL;

        //Predecode, ie bundle up an ExtMachInst
        //This should go away once the constructor can be set up properly
        predecoder.setTC(thread->getTC());
        //If more fetch data is needed, pass it in.
        if(predecoder.needMoreBytes())
            predecoder.moreBytes(thread->readPC(), 0, inst);
        else
            predecoder.process();
        //If an instruction is ready, decode it
        if (predecoder.extMachInstReady())
            instPtr = StaticInst::decode(predecoder.getExtMachInst());

        //If we decoded an instruction and it's microcoded, start pulling
        //out micro ops
        if (instPtr && instPtr->isMacroOp()) {
            curMacroStaticInst = instPtr;
            curStaticInst = curMacroStaticInst->
                fetchMicroOp(thread->readMicroPC());
        } else {
            curStaticInst = instPtr;
        }
    } else {
        //Read the next micro op from the macro op
        curStaticInst = curMacroStaticInst->
            fetchMicroOp(thread->readMicroPC());
    }

    //If we decoded an instruction this "tick", record information about it.
    if(curStaticInst)
    {
        traceData = Trace::getInstRecord(curTick, tc, curStaticInst,
                                         thread->readPC());

        DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
                curStaticInst->getName(), curStaticInst->machInst);

#if FULL_SYSTEM
        thread->setInst(inst);
#endif // FULL_SYSTEM
    }
}

void
BaseSimpleCPU::postExecute()
{
#if FULL_SYSTEM
    if (thread->profile) {
        bool usermode = TheISA::inUserMode(tc);
        thread->profilePC = usermode ? 1 : thread->readPC();
        StaticInstPtr si(inst);
        ProfileNode *node = thread->profile->consume(tc, si);
        if (node)
            thread->profileNode = node;
    }
#endif

    if (curStaticInst->isMemRef()) {
        numMemRefs++;
    }

    if (curStaticInst->isLoad()) {
        ++numLoad;
        comLoadEventQueue[0]->serviceEvents(numLoad);
    }

    traceFunctions(thread->readPC());

    if (traceData) {
        traceData->dump();
        delete traceData;
        traceData = NULL;
    }
}

void
BaseSimpleCPU::advancePC(Fault fault)
{
    if (fault != NoFault) {
        curMacroStaticInst = StaticInst::nullStaticInstPtr;
        fault->invoke(tc);
        thread->setMicroPC(0);
        thread->setNextMicroPC(1);
    } else if (predecoder.needMoreBytes()) {
        //If we're at the last micro op for this instruction
        if (curStaticInst && curStaticInst->isLastMicroOp()) {
            //We should be working with a macro op
            assert(curMacroStaticInst);
            //Close out this macro op, and clean up the
            //microcode state
            curMacroStaticInst = StaticInst::nullStaticInstPtr;
            thread->setMicroPC(0);
            thread->setNextMicroPC(1);
        }
        //If we're still in a macro op
        if (curMacroStaticInst) {
            //Advance the micro pc
            thread->setMicroPC(thread->readNextMicroPC());
            //Advance the "next" micro pc. Note that there are no delay
            //slots, and micro ops are "word" addressed.
            thread->setNextMicroPC(thread->readNextMicroPC() + 1);
        } else {
            // go to the next instruction
            thread->setPC(thread->readNextPC());
            thread->setNextPC(thread->readNextNPC());
            thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
            assert(thread->readNextPC() != thread->readNextNPC());
        }
    }

#if FULL_SYSTEM
    Addr oldpc;
    do {
        oldpc = thread->readPC();
        system->pcEventQueue.service(tc);
    } while (oldpc != thread->readPC());
#endif
}

<|endoftext|>


<commit_before>#include "compass_filter.hpp"
#include "location_state.hpp"

#include "../geometry/angles.hpp"

#include "../base/logging.hpp"

#include "../platform/location.hpp"

#define LOW_PASS_FACTOR 0.5

CompassFilter::CompassFilter()
{
  m_headingRad = m_smoothedHeadingRad = 0;

  // Set hard smoothing treshold constant to 10 degrees.
  // We can't assign it from location::CompassInfo::accuracy, because actually it's a
  // declination between magnetic and true north in Android
  // (and it may be very large in particular places on the Earth).
  m_smoothingThreshold = ang::DegreeToRad(10);
}

void CompassFilter::OnCompassUpdate(location::CompassInfo const & info)
{
  double const newHeadingRad = ((info.m_trueHeading >= 0.0) ? info.m_trueHeading : info.m_magneticHeading);
  double const newHeadingDelta = fabs(newHeadingRad - m_headingRad);

#ifdef OMIM_OS_IPHONE

  // On iOS we shouldn't smooth the compass values.

  m_headingRad = newHeadingRad;

#else
  // if new heading lies outside the twice treshold radius we immediately accept it
  if (newHeadingDelta > 2.0 * m_smoothingThreshold)
  {
    m_headingRad = newHeadingRad;
    m_smoothedHeadingRad = newHeadingRad;
  }
  else
  {
    // else we smooth the received value with the following formula
    // O(n) = O(n-1) + k * (I - O(n - 1));
    m_smoothedHeadingRad = m_smoothedHeadingRad + LOW_PASS_FACTOR * (newHeadingRad - m_smoothedHeadingRad);

    // if the change is too small we won't change the compass value
    if (newHeadingDelta > m_smoothingThreshold)
      m_headingRad = m_smoothedHeadingRad;
  }

#endif
}

double CompassFilter::GetHeadingRad() const
{
  return m_headingRad;
}

double CompassFilter::GetHeadingHalfErrorRad() const
{
  return m_smoothingThreshold;
}
<commit_msg>Fix warning.<commit_after>#include "compass_filter.hpp"
#include "location_state.hpp"

#include "../geometry/angles.hpp"

#include "../base/logging.hpp"

#include "../platform/location.hpp"

#define LOW_PASS_FACTOR 0.5

CompassFilter::CompassFilter()
{
  m_headingRad = m_smoothedHeadingRad = 0;

  // Set hard smoothing treshold constant to 10 degrees.
  // We can't assign it from location::CompassInfo::accuracy, because actually it's a
  // declination between magnetic and true north in Android
  // (and it may be very large in particular places on the Earth).
  m_smoothingThreshold = ang::DegreeToRad(10);
}

void CompassFilter::OnCompassUpdate(location::CompassInfo const & info)
{
  double const newHeadingRad = ((info.m_trueHeading >= 0.0) ? info.m_trueHeading : info.m_magneticHeading);

#ifdef OMIM_OS_IPHONE

  // On iOS we shouldn't smooth the compass values.

  m_headingRad = newHeadingRad;

#else

  double const newHeadingDelta = fabs(newHeadingRad - m_headingRad);

  // if new heading lies outside the twice treshold radius we immediately accept it
  if (newHeadingDelta > 2.0 * m_smoothingThreshold)
  {
    m_headingRad = newHeadingRad;
    m_smoothedHeadingRad = newHeadingRad;
  }
  else
  {
    // else we smooth the received value with the following formula
    // O(n) = O(n-1) + k * (I - O(n - 1));
    m_smoothedHeadingRad = m_smoothedHeadingRad + LOW_PASS_FACTOR * (newHeadingRad - m_smoothedHeadingRad);

    // if the change is too small we won't change the compass value
    if (newHeadingDelta > m_smoothingThreshold)
      m_headingRad = m_smoothedHeadingRad;
  }

#endif
}

double CompassFilter::GetHeadingRad() const
{
  return m_headingRad;
}

double CompassFilter::GetHeadingHalfErrorRad() const
{
  return m_smoothingThreshold;
}
<|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/renderer/autofill/autofill_agent.h"

#include "base/utf_string_conversions.h"
#include "chrome/common/autofill_messages.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/renderer/autofill/password_autofill_manager.h"
#include "chrome/renderer/render_view.h"
#include "grit/generated_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"

using WebKit::WebFormControlElement;
using WebKit::WebFormElement;
using WebKit::WebFrame;
using WebKit::WebInputElement;
using WebKit::WebKeyboardEvent;
using WebKit::WebNode;
using WebKit::WebString;

namespace {

// The size above which we stop triggering autofill for an input text field
// (so to avoid sending long strings through IPC).
const size_t kMaximumTextSizeForAutoFill = 1000;

}  // namespace

namespace autofill {

AutoFillAgent::AutoFillAgent(
    RenderView* render_view,
    PasswordAutoFillManager* password_autofill_manager)
    : RenderViewObserver(render_view),
      password_autofill_manager_(password_autofill_manager),
      autofill_query_id_(0),
      autofill_action_(AUTOFILL_NONE),
      display_warning_if_disabled_(false),
      was_query_node_autofilled_(false),
      suggestions_clear_index_(-1),
      suggestions_options_index_(-1),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}

AutoFillAgent::~AutoFillAgent() {}

bool AutoFillAgent::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(AutoFillAgent, message)
    IPC_MESSAGE_HANDLER(AutoFillMsg_SuggestionsReturned, OnSuggestionsReturned)
    IPC_MESSAGE_HANDLER(AutoFillMsg_FormDataFilled, OnFormDataFilled)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void AutoFillAgent::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
  // The document has now been fully loaded.  Scan for forms to be sent up to
  // the browser.
  form_manager_.ExtractForms(frame);
  SendForms(frame);
}

void AutoFillAgent::FrameDetached(WebKit::WebFrame* frame) {
  form_manager_.ResetFrame(frame);
}

void AutoFillAgent::FrameWillClose(WebKit::WebFrame* frame) {
  form_manager_.ResetFrame(frame);
}

void AutoFillAgent::FrameTranslated(WebKit::WebFrame* frame) {
  // The page is translated, so try to extract the form data again.
  DidFinishDocumentLoad(frame);
}

bool AutoFillAgent::InputElementClicked(const WebInputElement& element,
                                        bool was_focused,
                                        bool is_focused) {
  if (was_focused)
    ShowSuggestions(element, true, false, true);
  return false;
}

void AutoFillAgent::didAcceptAutoFillSuggestion(const WebKit::WebNode& node,
                                                const WebKit::WebString& value,
                                                const WebKit::WebString& label,
                                                int unique_id,
                                                unsigned index) {
  if (suggestions_options_index_ != -1 &&
      index == static_cast<unsigned>(suggestions_options_index_)) {
    // User selected 'AutoFill Options'.
    Send(new AutoFillHostMsg_ShowAutoFillDialog(routing_id()));
  } else if (suggestions_clear_index_ != -1 &&
             index == static_cast<unsigned>(suggestions_clear_index_)) {
    // User selected 'Clear form'.
    form_manager_.ClearFormWithNode(node);
  } else if (!unique_id) {
    // User selected an Autocomplete entry, so we fill directly.
    WebInputElement element = node.toConst<WebInputElement>();

    string16 substring = value;
    substring = substring.substr(0, element.maxLength());
    element.setValue(substring);

    WebFrame* webframe = node.document().frame();
    if (webframe)
      webframe->notifiyPasswordListenerOfAutocomplete(element);
  } else {
    // Fill the values for the whole form.
    FillAutoFillFormData(node, unique_id, AUTOFILL_FILL);
  }

  suggestions_clear_index_ = -1;
  suggestions_options_index_ = -1;
}

void AutoFillAgent::didSelectAutoFillSuggestion(const WebKit::WebNode& node,
                                                const WebKit::WebString& value,
                                                const WebKit::WebString& label,
                                                int unique_id) {
  DCHECK_GE(unique_id, 0);
  if (password_autofill_manager_->DidSelectAutoFillSuggestion(node, value))
    return;

  didClearAutoFillSelection(node);
  FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW);
}

void AutoFillAgent::didClearAutoFillSelection(const WebKit::WebNode& node) {
  form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_);
}

void AutoFillAgent::removeAutocompleteSuggestion(
    const WebKit::WebString& name,
    const WebKit::WebString& value) {
  // The index of clear & options will have shifted down.
  if (suggestions_clear_index_ != -1)
    suggestions_clear_index_--;
  if (suggestions_options_index_ != -1)
    suggestions_options_index_--;

  Send(new AutoFillHostMsg_RemoveAutocompleteEntry(routing_id(), name, value));
}

void AutoFillAgent::textFieldDidEndEditing(
    const WebKit::WebInputElement& element) {
  password_autofill_manager_->TextFieldDidEndEditing(element);
}

void AutoFillAgent::textFieldDidChange(const WebKit::WebInputElement& element) {
  // We post a task for doing the AutoFill as the caret position is not set
  // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and
  // it is needed to trigger autofill.
  method_factory_.RevokeAll();
  MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &AutoFillAgent::TextFieldDidChangeImpl, element));
}

void AutoFillAgent::TextFieldDidChangeImpl(
    const WebKit::WebInputElement& element) {
  if (password_autofill_manager_->TextDidChangeInTextField(element))
    return;

  ShowSuggestions(element, false, true, false);
}

void AutoFillAgent::textFieldDidReceiveKeyDown(
    const WebKit::WebInputElement& element,
    const WebKit::WebKeyboardEvent& event) {
  if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event))
    return;

  if (event.windowsKeyCode == ui::VKEY_DOWN ||
      event.windowsKeyCode == ui::VKEY_UP)
    ShowSuggestions(element, true, true, true);
}

void AutoFillAgent::OnSuggestionsReturned(int query_id,
                                          const std::vector<string16>& values,
                                          const std::vector<string16>& labels,
                                          const std::vector<string16>& icons,
                                          const std::vector<int>& unique_ids) {
  WebKit::WebView* web_view = render_view()->webview();
  if (!web_view || query_id != autofill_query_id_)
    return;

  if (values.empty()) {
    // No suggestions, any popup currently showing is obsolete.
    web_view->hidePopups();
    return;
  }

  std::vector<string16> v(values);
  std::vector<string16> l(labels);
  std::vector<string16> i(icons);
  std::vector<int> ids(unique_ids);
  int separator_index = -1;

  if (ids[0] < 0 && ids.size() > 1) {
    // If we received a warning instead of suggestions from autofill but regular
    // suggestions from autocomplete, don't show the autofill warning.
    v.erase(v.begin());
    l.erase(l.begin());
    i.erase(i.begin());
    ids.erase(ids.begin());
  }

  // If we were about to show a warning and we shouldn't, don't.
  if (ids[0] < 0 && !display_warning_if_disabled_)
    return;

  // Only include "AutoFill Options" special menu item if we have AutoFill
  // items, identified by |unique_ids| having at least one valid value.
  bool has_autofill_item = false;
  for (size_t i = 0; i < ids.size(); ++i) {
    if (ids[i] > 0) {
      has_autofill_item = true;
      break;
    }
  }

  // The form has been auto-filled, so give the user the chance to clear the
  // form.  Append the 'Clear form' menu item.
  if (has_autofill_item &&
      form_manager_.FormWithNodeIsAutoFilled(autofill_query_node_)) {
    v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
    l.push_back(string16());
    i.push_back(string16());
    ids.push_back(0);
    suggestions_clear_index_ = v.size() - 1;
    separator_index = v.size() - 1;
  }

  if (has_autofill_item) {
    // Append the 'Chrome Autofill options' menu item;
    v.push_back(l10n_util::GetStringFUTF16(IDS_AUTOFILL_OPTIONS_POPUP,
        WideToUTF16(chrome::kBrowserAppName)));
    l.push_back(string16());
    i.push_back(string16());
    ids.push_back(0);
    suggestions_options_index_ = v.size() - 1;
    separator_index = values.size();
  }

  // Send to WebKit for display.
  if (!v.empty() && autofill_query_node_.hasNonEmptyBoundingBox()) {
    web_view->applyAutoFillSuggestions(
        autofill_query_node_, v, l, i, ids, separator_index);
  }

  Send(new AutoFillHostMsg_DidShowAutoFillSuggestions(routing_id()));
}

void AutoFillAgent::OnFormDataFilled(int query_id,
                                     const webkit_glue::FormData& form) {
  if (!render_view()->webview() || query_id != autofill_query_id_)
    return;

  switch (autofill_action_) {
    case AUTOFILL_FILL:
      form_manager_.FillForm(form, autofill_query_node_);
      break;
    case AUTOFILL_PREVIEW:
      form_manager_.PreviewForm(form, autofill_query_node_);
      break;
    default:
      NOTREACHED();
  }
  autofill_action_ = AUTOFILL_NONE;
  Send(new AutoFillHostMsg_DidFillAutoFillFormData(routing_id()));
}

void AutoFillAgent::ShowSuggestions(const WebInputElement& element,
                                    bool autofill_on_empty_values,
                                    bool requires_caret_at_end,
                                    bool display_warning_if_disabled) {
  if (!element.isEnabledFormControl() || !element.isTextField() ||
      element.isPasswordField() || element.isReadOnly() ||
      !element.autoComplete())
    return;

  // If the field has no name, then we won't have values.
  if (element.nameForAutofill().isEmpty())
    return;

  // Don't attempt to autofill with values that are too large.
  WebString value = element.value();
  if (value.length() > kMaximumTextSizeForAutoFill)
    return;

  if (!autofill_on_empty_values && value.isEmpty())
    return;

  if (requires_caret_at_end &&
      (element.selectionStart() != element.selectionEnd() ||
       element.selectionEnd() != static_cast<int>(value.length())))
    return;

  QueryAutoFillSuggestions(element, display_warning_if_disabled);
}

void AutoFillAgent::QueryAutoFillSuggestions(const WebNode& node,
                                             bool display_warning_if_disabled) {
  static int query_counter = 0;
  autofill_query_id_ = query_counter++;
  autofill_query_node_ = node;
  display_warning_if_disabled_ = display_warning_if_disabled;

  webkit_glue::FormData form;
  webkit_glue::FormField field;
  if (!FindFormAndFieldForNode(node, &form, &field)) {
    // If we didn't find the cached form, at least let autocomplete have a shot
    // at providing suggestions.
    FormManager::WebFormControlElementToFormField(
        node.toConst<WebFormControlElement>(), FormManager::EXTRACT_VALUE,
        &field);
  }

  Send(new AutoFillHostMsg_QueryFormFieldAutoFill(
      routing_id(), autofill_query_id_, form, field));
}

void AutoFillAgent::FillAutoFillFormData(const WebNode& node,
                                         int unique_id,
                                         AutoFillAction action) {
  static int query_counter = 0;
  autofill_query_id_ = query_counter++;

  webkit_glue::FormData form;
  webkit_glue::FormField field;
  if (!FindFormAndFieldForNode(node, &form, &field))
    return;

  autofill_action_ = action;
  was_query_node_autofilled_ = field.is_autofilled();
  Send(new AutoFillHostMsg_FillAutoFillFormData(
      routing_id(), autofill_query_id_, form, field, unique_id));
}

void AutoFillAgent::SendForms(WebFrame* frame) {
  std::vector<webkit_glue::FormData> forms;
  form_manager_.GetFormsInFrame(frame, FormManager::REQUIRE_NONE, &forms);

  if (!forms.empty())
    Send(new AutoFillHostMsg_FormsSeen(routing_id(), forms));
}

bool AutoFillAgent::FindFormAndFieldForNode(const WebNode& node,
                                            webkit_glue::FormData* form,
                                            webkit_glue::FormField* field) {
  const WebInputElement& element = node.toConst<WebInputElement>();
  if (!form_manager_.FindFormWithFormControlElement(element,
                                                    FormManager::REQUIRE_NONE,
                                                    form))
    return false;

  FormManager::WebFormControlElementToFormField(element,
                                                FormManager::EXTRACT_VALUE,
                                                field);

  // WebFormControlElementToFormField does not scrape the DOM for the field
  // label, so find the label here.
  // TODO(jhawkins): Add form and field identities so we can use the cached form
  // data in FormManager.
  field->set_label(FormManager::LabelForElement(element));

  return true;
}

}  // namespace autofill
<commit_msg>Autofill crasher Chrome:+Crash+Report+-+Stack+Signature:+WebCore::Node::renderBoxModelObject()<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/renderer/autofill/autofill_agent.h"

#include "base/utf_string_conversions.h"
#include "chrome/common/autofill_messages.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/renderer/autofill/password_autofill_manager.h"
#include "chrome/renderer/render_view.h"
#include "grit/generated_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/form_field.h"
#include "webkit/glue/password_form.h"

using WebKit::WebFormControlElement;
using WebKit::WebFormElement;
using WebKit::WebFrame;
using WebKit::WebInputElement;
using WebKit::WebKeyboardEvent;
using WebKit::WebNode;
using WebKit::WebString;

namespace {

// The size above which we stop triggering autofill for an input text field
// (so to avoid sending long strings through IPC).
const size_t kMaximumTextSizeForAutoFill = 1000;

}  // namespace

namespace autofill {

AutoFillAgent::AutoFillAgent(
    RenderView* render_view,
    PasswordAutoFillManager* password_autofill_manager)
    : RenderViewObserver(render_view),
      password_autofill_manager_(password_autofill_manager),
      autofill_query_id_(0),
      autofill_action_(AUTOFILL_NONE),
      display_warning_if_disabled_(false),
      was_query_node_autofilled_(false),
      suggestions_clear_index_(-1),
      suggestions_options_index_(-1),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
}

AutoFillAgent::~AutoFillAgent() {}

bool AutoFillAgent::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(AutoFillAgent, message)
    IPC_MESSAGE_HANDLER(AutoFillMsg_SuggestionsReturned, OnSuggestionsReturned)
    IPC_MESSAGE_HANDLER(AutoFillMsg_FormDataFilled, OnFormDataFilled)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void AutoFillAgent::DidFinishDocumentLoad(WebKit::WebFrame* frame) {
  // The document has now been fully loaded.  Scan for forms to be sent up to
  // the browser.
  form_manager_.ExtractForms(frame);
  SendForms(frame);
}

void AutoFillAgent::FrameDetached(WebKit::WebFrame* frame) {
  form_manager_.ResetFrame(frame);
}

void AutoFillAgent::FrameWillClose(WebKit::WebFrame* frame) {
  form_manager_.ResetFrame(frame);
}

void AutoFillAgent::FrameTranslated(WebKit::WebFrame* frame) {
  // The page is translated, so try to extract the form data again.
  DidFinishDocumentLoad(frame);
}

bool AutoFillAgent::InputElementClicked(const WebInputElement& element,
                                        bool was_focused,
                                        bool is_focused) {
  if (was_focused)
    ShowSuggestions(element, true, false, true);
  return false;
}

void AutoFillAgent::didAcceptAutoFillSuggestion(const WebKit::WebNode& node,
                                                const WebKit::WebString& value,
                                                const WebKit::WebString& label,
                                                int unique_id,
                                                unsigned index) {
  if (suggestions_options_index_ != -1 &&
      index == static_cast<unsigned>(suggestions_options_index_)) {
    // User selected 'AutoFill Options'.
    Send(new AutoFillHostMsg_ShowAutoFillDialog(routing_id()));
  } else if (suggestions_clear_index_ != -1 &&
             index == static_cast<unsigned>(suggestions_clear_index_)) {
    // User selected 'Clear form'.
    form_manager_.ClearFormWithNode(node);
  } else if (!unique_id) {
    // User selected an Autocomplete entry, so we fill directly.
    WebInputElement element = node.toConst<WebInputElement>();

    string16 substring = value;
    substring = substring.substr(0, element.maxLength());
    element.setValue(substring);

    WebFrame* webframe = node.document().frame();
    if (webframe)
      webframe->notifiyPasswordListenerOfAutocomplete(element);
  } else {
    // Fill the values for the whole form.
    FillAutoFillFormData(node, unique_id, AUTOFILL_FILL);
  }

  suggestions_clear_index_ = -1;
  suggestions_options_index_ = -1;
}

void AutoFillAgent::didSelectAutoFillSuggestion(const WebKit::WebNode& node,
                                                const WebKit::WebString& value,
                                                const WebKit::WebString& label,
                                                int unique_id) {
  DCHECK_GE(unique_id, 0);
  if (password_autofill_manager_->DidSelectAutoFillSuggestion(node, value))
    return;

  didClearAutoFillSelection(node);
  FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW);
}

void AutoFillAgent::didClearAutoFillSelection(const WebKit::WebNode& node) {
  form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_);
}

void AutoFillAgent::removeAutocompleteSuggestion(
    const WebKit::WebString& name,
    const WebKit::WebString& value) {
  // The index of clear & options will have shifted down.
  if (suggestions_clear_index_ != -1)
    suggestions_clear_index_--;
  if (suggestions_options_index_ != -1)
    suggestions_options_index_--;

  Send(new AutoFillHostMsg_RemoveAutocompleteEntry(routing_id(), name, value));
}

void AutoFillAgent::textFieldDidEndEditing(
    const WebKit::WebInputElement& element) {
  password_autofill_manager_->TextFieldDidEndEditing(element);
}

void AutoFillAgent::textFieldDidChange(const WebKit::WebInputElement& element) {
  // We post a task for doing the AutoFill as the caret position is not set
  // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and
  // it is needed to trigger autofill.
  method_factory_.RevokeAll();
  MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &AutoFillAgent::TextFieldDidChangeImpl, element));
}

void AutoFillAgent::TextFieldDidChangeImpl(
    const WebKit::WebInputElement& element) {
  if (password_autofill_manager_->TextDidChangeInTextField(element))
    return;

  ShowSuggestions(element, false, true, false);
}

void AutoFillAgent::textFieldDidReceiveKeyDown(
    const WebKit::WebInputElement& element,
    const WebKit::WebKeyboardEvent& event) {
  if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event))
    return;

  if (event.windowsKeyCode == ui::VKEY_DOWN ||
      event.windowsKeyCode == ui::VKEY_UP)
    ShowSuggestions(element, true, true, true);
}

void AutoFillAgent::OnSuggestionsReturned(int query_id,
                                          const std::vector<string16>& values,
                                          const std::vector<string16>& labels,
                                          const std::vector<string16>& icons,
                                          const std::vector<int>& unique_ids) {
  WebKit::WebView* web_view = render_view()->webview();
  if (!web_view || query_id != autofill_query_id_)
    return;

  if (values.empty()) {
    // No suggestions, any popup currently showing is obsolete.
    web_view->hidePopups();
    return;
  }

  std::vector<string16> v(values);
  std::vector<string16> l(labels);
  std::vector<string16> i(icons);
  std::vector<int> ids(unique_ids);
  int separator_index = -1;

  if (ids[0] < 0 && ids.size() > 1) {
    // If we received a warning instead of suggestions from autofill but regular
    // suggestions from autocomplete, don't show the autofill warning.
    v.erase(v.begin());
    l.erase(l.begin());
    i.erase(i.begin());
    ids.erase(ids.begin());
  }

  // If we were about to show a warning and we shouldn't, don't.
  if (ids[0] < 0 && !display_warning_if_disabled_)
    return;

  // Only include "AutoFill Options" special menu item if we have AutoFill
  // items, identified by |unique_ids| having at least one valid value.
  bool has_autofill_item = false;
  for (size_t i = 0; i < ids.size(); ++i) {
    if (ids[i] > 0) {
      has_autofill_item = true;
      break;
    }
  }

  // The form has been auto-filled, so give the user the chance to clear the
  // form.  Append the 'Clear form' menu item.
  if (has_autofill_item &&
      form_manager_.FormWithNodeIsAutoFilled(autofill_query_node_)) {
    v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
    l.push_back(string16());
    i.push_back(string16());
    ids.push_back(0);
    suggestions_clear_index_ = v.size() - 1;
    separator_index = v.size() - 1;
  }

  if (has_autofill_item) {
    // Append the 'Chrome Autofill options' menu item;
    v.push_back(l10n_util::GetStringFUTF16(IDS_AUTOFILL_OPTIONS_POPUP,
        WideToUTF16(chrome::kBrowserAppName)));
    l.push_back(string16());
    i.push_back(string16());
    ids.push_back(0);
    suggestions_options_index_ = v.size() - 1;
    separator_index = values.size();
  }

  // Send to WebKit for display.
  if (!v.empty() && !autofill_query_node_.isNull() &&
      autofill_query_node_.hasNonEmptyBoundingBox()) {
    web_view->applyAutoFillSuggestions(
        autofill_query_node_, v, l, i, ids, separator_index);
  }

  Send(new AutoFillHostMsg_DidShowAutoFillSuggestions(routing_id()));
}

void AutoFillAgent::OnFormDataFilled(int query_id,
                                     const webkit_glue::FormData& form) {
  if (!render_view()->webview() || query_id != autofill_query_id_)
    return;

  switch (autofill_action_) {
    case AUTOFILL_FILL:
      form_manager_.FillForm(form, autofill_query_node_);
      break;
    case AUTOFILL_PREVIEW:
      form_manager_.PreviewForm(form, autofill_query_node_);
      break;
    default:
      NOTREACHED();
  }
  autofill_action_ = AUTOFILL_NONE;
  Send(new AutoFillHostMsg_DidFillAutoFillFormData(routing_id()));
}

void AutoFillAgent::ShowSuggestions(const WebInputElement& element,
                                    bool autofill_on_empty_values,
                                    bool requires_caret_at_end,
                                    bool display_warning_if_disabled) {
  if (!element.isEnabledFormControl() || !element.isTextField() ||
      element.isPasswordField() || element.isReadOnly() ||
      !element.autoComplete())
    return;

  // If the field has no name, then we won't have values.
  if (element.nameForAutofill().isEmpty())
    return;

  // Don't attempt to autofill with values that are too large.
  WebString value = element.value();
  if (value.length() > kMaximumTextSizeForAutoFill)
    return;

  if (!autofill_on_empty_values && value.isEmpty())
    return;

  if (requires_caret_at_end &&
      (element.selectionStart() != element.selectionEnd() ||
       element.selectionEnd() != static_cast<int>(value.length())))
    return;

  QueryAutoFillSuggestions(element, display_warning_if_disabled);
}

void AutoFillAgent::QueryAutoFillSuggestions(const WebNode& node,
                                             bool display_warning_if_disabled) {
  static int query_counter = 0;
  autofill_query_id_ = query_counter++;
  autofill_query_node_ = node;
  display_warning_if_disabled_ = display_warning_if_disabled;

  webkit_glue::FormData form;
  webkit_glue::FormField field;
  if (!FindFormAndFieldForNode(node, &form, &field)) {
    // If we didn't find the cached form, at least let autocomplete have a shot
    // at providing suggestions.
    FormManager::WebFormControlElementToFormField(
        node.toConst<WebFormControlElement>(), FormManager::EXTRACT_VALUE,
        &field);
  }

  Send(new AutoFillHostMsg_QueryFormFieldAutoFill(
      routing_id(), autofill_query_id_, form, field));
}

void AutoFillAgent::FillAutoFillFormData(const WebNode& node,
                                         int unique_id,
                                         AutoFillAction action) {
  static int query_counter = 0;
  autofill_query_id_ = query_counter++;

  webkit_glue::FormData form;
  webkit_glue::FormField field;
  if (!FindFormAndFieldForNode(node, &form, &field))
    return;

  autofill_action_ = action;
  was_query_node_autofilled_ = field.is_autofilled();
  Send(new AutoFillHostMsg_FillAutoFillFormData(
      routing_id(), autofill_query_id_, form, field, unique_id));
}

void AutoFillAgent::SendForms(WebFrame* frame) {
  std::vector<webkit_glue::FormData> forms;
  form_manager_.GetFormsInFrame(frame, FormManager::REQUIRE_NONE, &forms);

  if (!forms.empty())
    Send(new AutoFillHostMsg_FormsSeen(routing_id(), forms));
}

bool AutoFillAgent::FindFormAndFieldForNode(const WebNode& node,
                                            webkit_glue::FormData* form,
                                            webkit_glue::FormField* field) {
  const WebInputElement& element = node.toConst<WebInputElement>();
  if (!form_manager_.FindFormWithFormControlElement(element,
                                                    FormManager::REQUIRE_NONE,
                                                    form))
    return false;

  FormManager::WebFormControlElementToFormField(element,
                                                FormManager::EXTRACT_VALUE,
                                                field);

  // WebFormControlElementToFormField does not scrape the DOM for the field
  // label, so find the label here.
  // TODO(jhawkins): Add form and field identities so we can use the cached form
  // data in FormManager.
  field->set_label(FormManager::LabelForElement(element));

  return true;
}

}  // namespace autofill
<|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/renderer/pepper_scrollbar_widget.h"

#include "base/basictypes.h"
#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "chrome/renderer/pepper_devices.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/platform_device.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScrollBar.h"
#include "webkit/glue/plugins/plugin_instance.h"

using WebKit::WebInputEvent;
using WebKit::WebKeyboardEvent;
using WebKit::WebMouseEvent;
using WebKit::WebMouseWheelEvent;
using WebKit::WebRect;
using WebKit::WebScrollbar;
using WebKit::WebVector;

// Anonymous namespace for functions converting NPAPI to WebInputEvents types.
namespace {

WebKeyboardEvent BuildKeyEvent(const NPPepperEvent& event) {
  WebKeyboardEvent key_event;
  switch (event.type) {
    case NPEventType_RawKeyDown:
      key_event.type = WebInputEvent::RawKeyDown;
      break;
    case NPEventType_KeyDown:
      key_event.type = WebInputEvent::KeyDown;
      break;
    case NPEventType_KeyUp:
      key_event.type = WebInputEvent::KeyUp;
      break;
  }
  key_event.timeStampSeconds = event.timeStampSeconds;
  key_event.modifiers = event.u.key.modifier;
  key_event.windowsKeyCode = event.u.key.normalizedKeyCode;
  return key_event;
}

WebKeyboardEvent BuildCharEvent(const NPPepperEvent& event) {
  WebKeyboardEvent key_event;
  key_event.type = WebInputEvent::Char;
  key_event.timeStampSeconds = event.timeStampSeconds;
  key_event.modifiers = event.u.character.modifier;
  // For consistency, check that the sizes of the texts agree.
  DCHECK(sizeof(event.u.character.text) == sizeof(key_event.text));
  DCHECK(sizeof(event.u.character.unmodifiedText) ==
         sizeof(key_event.unmodifiedText));
  for (size_t i = 0; i < WebKeyboardEvent::textLengthCap; ++i) {
    key_event.text[i] = event.u.character.text[i];
    key_event.unmodifiedText[i] = event.u.character.unmodifiedText[i];
  }
  return key_event;
}

WebMouseEvent BuildMouseEvent(const NPPepperEvent& event) {
  WebMouseEvent mouse_event;
  switch (event.type) {
    case NPEventType_MouseDown:
      mouse_event.type = WebInputEvent::MouseDown;
      break;
    case NPEventType_MouseUp:
      mouse_event.type = WebInputEvent::MouseUp;
      break;
    case NPEventType_MouseMove:
      mouse_event.type = WebInputEvent::MouseMove;
      break;
    case NPEventType_MouseEnter:
      mouse_event.type = WebInputEvent::MouseEnter;
      break;
    case NPEventType_MouseLeave:
      mouse_event.type = WebInputEvent::MouseLeave;
      break;
  }
  mouse_event.timeStampSeconds = event.timeStampSeconds;
  mouse_event.modifiers = event.u.mouse.modifier;
  mouse_event.button = static_cast<WebMouseEvent::Button>(event.u.mouse.button);
  mouse_event.x = event.u.mouse.x;
  mouse_event.y = event.u.mouse.y;
  mouse_event.clickCount = event.u.mouse.clickCount;
  return mouse_event;
}

WebMouseWheelEvent BuildMouseWheelEvent(const NPPepperEvent& event) {
  WebMouseWheelEvent mouse_wheel_event;
  mouse_wheel_event.type = WebInputEvent::MouseWheel;
  mouse_wheel_event.timeStampSeconds = event.timeStampSeconds;
  mouse_wheel_event.modifiers = event.u.wheel.modifier;
  mouse_wheel_event.deltaX = event.u.wheel.deltaX;
  mouse_wheel_event.deltaY = event.u.wheel.deltaY;
  mouse_wheel_event.wheelTicksX = event.u.wheel.wheelTicksX;
  mouse_wheel_event.wheelTicksY = event.u.wheel.wheelTicksY;
  mouse_wheel_event.scrollByPage = event.u.wheel.scrollByPage;
  return mouse_wheel_event;
}

}  // namespace

PepperScrollbarWidget::PepperScrollbarWidget(
    const NPScrollbarCreateParams& params) {
  scrollbar_.reset(WebScrollbar::create(
    static_cast<WebKit::WebScrollbarClient*>(this),
    params.vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal));
  AddRef();
}

PepperScrollbarWidget::~PepperScrollbarWidget() {
}

void PepperScrollbarWidget::Destroy() {
  Release();
}

void PepperScrollbarWidget::Paint(Graphics2DDeviceContext* context,
                                  const NPRect& dirty) {
  gfx::Rect rect(dirty.left, dirty.top, dirty.right - dirty.left,
                 dirty.bottom - dirty.top);
#if defined(OS_WIN) || defined(OS_LINUX)
  scrollbar_->paint(context->canvas(), rect);
#elif defined(OS_MACOSX)
  // TODO(port)
#endif
  dirty_rect_ = dirty_rect_.Subtract(rect);
}

bool PepperScrollbarWidget::HandleEvent(const NPPepperEvent& event) {
  bool rv = false;

  switch (event.type) {
    case NPEventType_Undefined:
      return false;
    case NPEventType_MouseDown:
    case NPEventType_MouseUp:
    case NPEventType_MouseMove:
    case NPEventType_MouseEnter:
    case NPEventType_MouseLeave:
      rv = scrollbar_->handleInputEvent(BuildMouseEvent(event));
      break;
    case NPEventType_MouseWheel:
      rv = scrollbar_->handleInputEvent(BuildMouseWheelEvent(event));
      break;
    case NPEventType_RawKeyDown:
    case NPEventType_KeyDown:
    case NPEventType_KeyUp:
      rv = scrollbar_->handleInputEvent(BuildKeyEvent(event));
      break;
    case NPEventType_Char:
      rv = scrollbar_->handleInputEvent(BuildCharEvent(event));
      break;
    case NPEventType_Minimize:
    case NPEventType_Focus:
    case NPEventType_Device:
      // NOTIMPLEMENTED();
      break;
  }

  return rv;
}

void PepperScrollbarWidget::GetProperty(
    NPWidgetProperty property, void* value) {
  switch (property) {
    case NPWidgetPropertyLocation: {
      NPRect* rv = static_cast<NPRect*>(value);
      rv->left = location_.x();
      rv->top = location_.y();
      rv->right = location_.right();
      rv->bottom = location_.bottom();
      break;
    }
    case NPWidgetPropertyDirtyRect: {
      NPRect* rv = reinterpret_cast<NPRect*>(value);
      rv->left = dirty_rect_.x();
      rv->top = dirty_rect_.y();
      rv->right = dirty_rect_.right();
      rv->bottom = dirty_rect_.bottom();
      break;
    }
    case NPWidgetPropertyScrollbarThickness: {
      int32* rv = static_cast<int32*>(value);
      *rv = WebScrollbar::defaultThickness();
      break;
    }
    case NPWidgetPropertyScrollbarValue: {
      int32* rv = static_cast<int32*>(value);
      *rv = scrollbar_->value();
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

void PepperScrollbarWidget::SetProperty(
    NPWidgetProperty property, void* value) {
  switch (property) {
    case NPWidgetPropertyLocation: {
      NPRect* r = static_cast<NPRect*>(value);
      location_ = gfx::Rect(
          r->left, r->top, r->right - r->left, r->bottom - r->top);
      scrollbar_->setLocation(location_);
      break;
    }
    case NPWidgetPropertyScrollbarValue: {
      int32* position = static_cast<int*>(value);
      scrollbar_->setValue(*position);
      break;
    }
    case NPWidgetPropertyScrollbarDocumentSize: {
      int32* total_length = static_cast<int32*>(value);
      scrollbar_->setDocumentSize(*total_length);
      break;
    }
    case NPWidgetPropertyScrollbarTickMarks: {
      NPScrollbarTickMarks* tickmarks =
          static_cast<NPScrollbarTickMarks*>(value);
      tickmarks_.resize(tickmarks->count);
      for (uint32 i = 0; i < tickmarks->count; ++i) {
        WebRect rect(
            tickmarks->tickmarks[i].left,
            tickmarks->tickmarks[i].top,
            tickmarks->tickmarks[i].right - tickmarks->tickmarks[i].left,
            tickmarks->tickmarks[i].bottom - tickmarks->tickmarks[i].top);
        tickmarks_[i] = rect;
      }
      dirty_rect_ = location_;
      NotifyInvalidate();
      break;
    }
    case NPWidgetPropertyScrollbarScrollByLine:
    case NPWidgetPropertyScrollbarScrollByPage:
    case NPWidgetPropertyScrollbarScrollByDocument:
    case NPWidgetPropertyScrollbarScrollByPixels: {
      bool forward;
      float multiplier = 1.0;

      WebScrollbar::ScrollGranularity granularity;
      if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByLine;
      } else if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByPage;
      } else if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByDocument;
      } else {
        multiplier = static_cast<float>(*static_cast<int32*>(value));
        forward = multiplier >= 0;
        if (multiplier < 0)
          multiplier *= -1;
        granularity = WebScrollbar::ScrollByPixel;
      }
      scrollbar_->scroll(
          forward ? WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward,
          granularity, multiplier);
      break;
    }
  }
}

void PepperScrollbarWidget::valueChanged(WebScrollbar*) {
  WidgetPropertyChanged(NPWidgetPropertyScrollbarValue);
}

void PepperScrollbarWidget::invalidateScrollbarRect(WebScrollbar*,
                                                    const WebRect& rect) {
  dirty_rect_ = dirty_rect_.Union(rect);
  // Can't call into the client to tell them about the invalidate right away,
  // since the Scrollbar code is still in the middle of updating its internal
  // state.
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &PepperScrollbarWidget::NotifyInvalidate));
}

void PepperScrollbarWidget::getTickmarks(WebKit::WebScrollbar*,
                                         WebVector<WebRect>* tickmarks) const {
  if (tickmarks_.empty()) {
    WebRect* rects = NULL;
    tickmarks->assign(rects, 0);
  } else {
    tickmarks->assign(&tickmarks_[0], tickmarks_.size());
  }
}

void PepperScrollbarWidget::NotifyInvalidate() {
  if (!dirty_rect_.IsEmpty())
    WidgetPropertyChanged(NPWidgetPropertyDirtyRect);
}
<commit_msg>Fix Mac buildbreak<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/renderer/pepper_scrollbar_widget.h"

#include "base/basictypes.h"
#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "chrome/renderer/pepper_devices.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/platform_device.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScrollBar.h"
#include "webkit/glue/plugins/plugin_instance.h"

using WebKit::WebInputEvent;
using WebKit::WebKeyboardEvent;
using WebKit::WebMouseEvent;
using WebKit::WebMouseWheelEvent;
using WebKit::WebRect;
using WebKit::WebScrollbar;
using WebKit::WebVector;

// Anonymous namespace for functions converting NPAPI to WebInputEvents types.
namespace {

WebKeyboardEvent BuildKeyEvent(const NPPepperEvent& event) {
  WebKeyboardEvent key_event;
  switch (event.type) {
    case NPEventType_RawKeyDown:
      key_event.type = WebInputEvent::RawKeyDown;
      break;
    case NPEventType_KeyDown:
      key_event.type = WebInputEvent::KeyDown;
      break;
    case NPEventType_KeyUp:
      key_event.type = WebInputEvent::KeyUp;
      break;
  }
  key_event.timeStampSeconds = event.timeStampSeconds;
  key_event.modifiers = event.u.key.modifier;
  key_event.windowsKeyCode = event.u.key.normalizedKeyCode;
  return key_event;
}

WebKeyboardEvent BuildCharEvent(const NPPepperEvent& event) {
  WebKeyboardEvent key_event;
  key_event.type = WebInputEvent::Char;
  key_event.timeStampSeconds = event.timeStampSeconds;
  key_event.modifiers = event.u.character.modifier;
  // For consistency, check that the sizes of the texts agree.
  DCHECK(sizeof(event.u.character.text) == sizeof(key_event.text));
  DCHECK(sizeof(event.u.character.unmodifiedText) ==
         sizeof(key_event.unmodifiedText));
  for (size_t i = 0; i < WebKeyboardEvent::textLengthCap; ++i) {
    key_event.text[i] = event.u.character.text[i];
    key_event.unmodifiedText[i] = event.u.character.unmodifiedText[i];
  }
  return key_event;
}

WebMouseEvent BuildMouseEvent(const NPPepperEvent& event) {
  WebMouseEvent mouse_event;
  switch (event.type) {
    case NPEventType_MouseDown:
      mouse_event.type = WebInputEvent::MouseDown;
      break;
    case NPEventType_MouseUp:
      mouse_event.type = WebInputEvent::MouseUp;
      break;
    case NPEventType_MouseMove:
      mouse_event.type = WebInputEvent::MouseMove;
      break;
    case NPEventType_MouseEnter:
      mouse_event.type = WebInputEvent::MouseEnter;
      break;
    case NPEventType_MouseLeave:
      mouse_event.type = WebInputEvent::MouseLeave;
      break;
  }
  mouse_event.timeStampSeconds = event.timeStampSeconds;
  mouse_event.modifiers = event.u.mouse.modifier;
  mouse_event.button = static_cast<WebMouseEvent::Button>(event.u.mouse.button);
  mouse_event.x = event.u.mouse.x;
  mouse_event.y = event.u.mouse.y;
  mouse_event.clickCount = event.u.mouse.clickCount;
  return mouse_event;
}

WebMouseWheelEvent BuildMouseWheelEvent(const NPPepperEvent& event) {
  WebMouseWheelEvent mouse_wheel_event;
  mouse_wheel_event.type = WebInputEvent::MouseWheel;
  mouse_wheel_event.timeStampSeconds = event.timeStampSeconds;
  mouse_wheel_event.modifiers = event.u.wheel.modifier;
  mouse_wheel_event.deltaX = event.u.wheel.deltaX;
  mouse_wheel_event.deltaY = event.u.wheel.deltaY;
  mouse_wheel_event.wheelTicksX = event.u.wheel.wheelTicksX;
  mouse_wheel_event.wheelTicksY = event.u.wheel.wheelTicksY;
  mouse_wheel_event.scrollByPage = event.u.wheel.scrollByPage;
  return mouse_wheel_event;
}

}  // namespace

PepperScrollbarWidget::PepperScrollbarWidget(
    const NPScrollbarCreateParams& params) {
  scrollbar_.reset(WebScrollbar::create(
    static_cast<WebKit::WebScrollbarClient*>(this),
    params.vertical ? WebScrollbar::Vertical : WebScrollbar::Horizontal));
  AddRef();
}

PepperScrollbarWidget::~PepperScrollbarWidget() {
}

void PepperScrollbarWidget::Destroy() {
  Release();
}

void PepperScrollbarWidget::Paint(Graphics2DDeviceContext* context,
                                  const NPRect& dirty) {
  gfx::Rect rect(dirty.left, dirty.top, dirty.right - dirty.left,
                 dirty.bottom - dirty.top);
#if defined(OS_WIN) || defined(OS_LINUX)
  scrollbar_->paint(context->canvas(), rect);
#elif defined(OS_MACOSX)
  // TODO(port)
#endif
  dirty_rect_ = dirty_rect_.Subtract(rect);
}

bool PepperScrollbarWidget::HandleEvent(const NPPepperEvent& event) {
  bool rv = false;

  switch (event.type) {
    case NPEventType_Undefined:
      return false;
    case NPEventType_MouseDown:
    case NPEventType_MouseUp:
    case NPEventType_MouseMove:
    case NPEventType_MouseEnter:
    case NPEventType_MouseLeave:
      rv = scrollbar_->handleInputEvent(BuildMouseEvent(event));
      break;
    case NPEventType_MouseWheel:
      rv = scrollbar_->handleInputEvent(BuildMouseWheelEvent(event));
      break;
    case NPEventType_RawKeyDown:
    case NPEventType_KeyDown:
    case NPEventType_KeyUp:
      rv = scrollbar_->handleInputEvent(BuildKeyEvent(event));
      break;
    case NPEventType_Char:
      rv = scrollbar_->handleInputEvent(BuildCharEvent(event));
      break;
    case NPEventType_Minimize:
    case NPEventType_Focus:
    case NPEventType_Device:
      // NOTIMPLEMENTED();
      break;
  }

  return rv;
}

void PepperScrollbarWidget::GetProperty(
    NPWidgetProperty property, void* value) {
  switch (property) {
    case NPWidgetPropertyLocation: {
      NPRect* rv = static_cast<NPRect*>(value);
      rv->left = location_.x();
      rv->top = location_.y();
      rv->right = location_.right();
      rv->bottom = location_.bottom();
      break;
    }
    case NPWidgetPropertyDirtyRect: {
      NPRect* rv = reinterpret_cast<NPRect*>(value);
      rv->left = dirty_rect_.x();
      rv->top = dirty_rect_.y();
      rv->right = dirty_rect_.right();
      rv->bottom = dirty_rect_.bottom();
      break;
    }
    case NPWidgetPropertyScrollbarThickness: {
      int32* rv = static_cast<int32*>(value);
      *rv = WebScrollbar::defaultThickness();
      break;
    }
    case NPWidgetPropertyScrollbarValue: {
      int32* rv = static_cast<int32*>(value);
      *rv = scrollbar_->value();
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

void PepperScrollbarWidget::SetProperty(
    NPWidgetProperty property, void* value) {
  switch (property) {
    case NPWidgetPropertyLocation: {
      NPRect* r = static_cast<NPRect*>(value);
      location_ = gfx::Rect(
          r->left, r->top, r->right - r->left, r->bottom - r->top);
      scrollbar_->setLocation(location_);
      break;
    }
    case NPWidgetPropertyScrollbarValue: {
      int32* position = static_cast<int*>(value);
      scrollbar_->setValue(*position);
      break;
    }
    case NPWidgetPropertyScrollbarDocumentSize: {
      int32* total_length = static_cast<int32*>(value);
      scrollbar_->setDocumentSize(*total_length);
      break;
    }
    case NPWidgetPropertyScrollbarTickMarks: {
      NPScrollbarTickMarks* tickmarks =
          static_cast<NPScrollbarTickMarks*>(value);
      tickmarks_.resize(tickmarks->count);
      for (uint32 i = 0; i < tickmarks->count; ++i) {
        WebRect rect(
            tickmarks->tickmarks[i].left,
            tickmarks->tickmarks[i].top,
            tickmarks->tickmarks[i].right - tickmarks->tickmarks[i].left,
            tickmarks->tickmarks[i].bottom - tickmarks->tickmarks[i].top);
        tickmarks_[i] = rect;
      }
      dirty_rect_ = location_;
      NotifyInvalidate();
      break;
    }
    case NPWidgetPropertyScrollbarScrollByLine:
    case NPWidgetPropertyScrollbarScrollByPage:
    case NPWidgetPropertyScrollbarScrollByDocument:
    case NPWidgetPropertyScrollbarScrollByPixels: {
      bool forward;
      float multiplier = 1.0;

      WebScrollbar::ScrollGranularity granularity;
      if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByLine;
      } else if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByPage;
      } else if (property == NPWidgetPropertyScrollbarScrollByLine) {
        forward = *static_cast<bool*>(value);
        granularity = WebScrollbar::ScrollByDocument;
      } else {
        multiplier = static_cast<float>(*static_cast<int32*>(value));
        forward = multiplier >= 0;
        if (multiplier < 0)
          multiplier *= -1;
        granularity = WebScrollbar::ScrollByPixel;
      }
      scrollbar_->scroll(
          forward ? WebScrollbar::ScrollForward : WebScrollbar::ScrollBackward,
          granularity, multiplier);
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

void PepperScrollbarWidget::valueChanged(WebScrollbar*) {
  WidgetPropertyChanged(NPWidgetPropertyScrollbarValue);
}

void PepperScrollbarWidget::invalidateScrollbarRect(WebScrollbar*,
                                                    const WebRect& rect) {
  dirty_rect_ = dirty_rect_.Union(rect);
  // Can't call into the client to tell them about the invalidate right away,
  // since the Scrollbar code is still in the middle of updating its internal
  // state.
  MessageLoop::current()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &PepperScrollbarWidget::NotifyInvalidate));
}

void PepperScrollbarWidget::getTickmarks(WebKit::WebScrollbar*,
                                         WebVector<WebRect>* tickmarks) const {
  if (tickmarks_.empty()) {
    WebRect* rects = NULL;
    tickmarks->assign(rects, 0);
  } else {
    tickmarks->assign(&tickmarks_[0], tickmarks_.size());
  }
}

void PepperScrollbarWidget::NotifyInvalidate() {
  if (!dirty_rect_.IsEmpty())
    WidgetPropertyChanged(NPWidgetPropertyDirtyRect);
}
<|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/renderer/speech_input_dispatcher.h"

#include "chrome/renderer/render_view.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputListener.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"

using WebKit::WebFrame;

SpeechInputDispatcher::SpeechInputDispatcher(
    RenderView* render_view, WebKit::WebSpeechInputListener* listener)
    : render_view_(render_view),
      listener_(listener) {
}

bool SpeechInputDispatcher::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SpeechInputDispatcher, message)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_SetRecognitionResult,
                        OnSpeechRecognitionResult)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecordingComplete,
                        OnSpeechRecordingComplete)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecognitionComplete,
                        OnSpeechRecognitionComplete)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

bool SpeechInputDispatcher::startRecognition(
    int request_id, const WebKit::WebString& language,
    const WebKit::WebRect& element_rect) {
  return startRecognition(request_id, element_rect);
}

bool SpeechInputDispatcher::startRecognition(
    int request_id, const WebKit::WebRect& element_rect) {
  VLOG(1) << "SpeechInputDispatcher::startRecognition enter";
  gfx::Size scroll = render_view_->webview()->mainFrame()->scrollOffset();
  gfx::Rect rect = element_rect;
  rect.Offset(-scroll.width(), -scroll.height());
  render_view_->Send(new ViewHostMsg_SpeechInput_StartRecognition(
      render_view_->routing_id(), request_id, rect));
  VLOG(1) << "SpeechInputDispatcher::startRecognition exit";
  return true;
}

void SpeechInputDispatcher::cancelRecognition(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::cancelRecognition enter";
  render_view_->Send(new ViewHostMsg_SpeechInput_CancelRecognition(
      render_view_->routing_id(), request_id));
  VLOG(1) << "SpeechInputDispatcher::cancelRecognition exit";
}

void SpeechInputDispatcher::stopRecording(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::stopRecording enter";
  render_view_->Send(new ViewHostMsg_SpeechInput_StopRecording(
      render_view_->routing_id(), request_id));
  VLOG(1) << "SpeechInputDispatcher::stopRecording exit";
}

void SpeechInputDispatcher::OnSpeechRecognitionResult(
    int request_id, const string16& result) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionResult enter";
  listener_->setRecognitionResult(request_id, result);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionResult exit";
}

void SpeechInputDispatcher::OnSpeechRecordingComplete(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecordingComplete enter";
  listener_->didCompleteRecording(request_id);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecordingComplete exit";
}

void SpeechInputDispatcher::OnSpeechRecognitionComplete(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionComplete enter";
  listener_->didCompleteRecognition(request_id);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionComplete exit";
}
<commit_msg>Construct a WebString explicitly and pass to a WebKit method. This is to prevent build errors when https://bugs.webkit.org/show_bug.cgi?id=48068 lands.<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/renderer/speech_input_dispatcher.h"

#include "chrome/renderer/render_view.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputListener.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"

using WebKit::WebFrame;

SpeechInputDispatcher::SpeechInputDispatcher(
    RenderView* render_view, WebKit::WebSpeechInputListener* listener)
    : render_view_(render_view),
      listener_(listener) {
}

bool SpeechInputDispatcher::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(SpeechInputDispatcher, message)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_SetRecognitionResult,
                        OnSpeechRecognitionResult)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecordingComplete,
                        OnSpeechRecordingComplete)
    IPC_MESSAGE_HANDLER(ViewMsg_SpeechInput_RecognitionComplete,
                        OnSpeechRecognitionComplete)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

bool SpeechInputDispatcher::startRecognition(
    int request_id, const WebKit::WebString& language,
    const WebKit::WebRect& element_rect) {
  return startRecognition(request_id, element_rect);
}

bool SpeechInputDispatcher::startRecognition(
    int request_id, const WebKit::WebRect& element_rect) {
  VLOG(1) << "SpeechInputDispatcher::startRecognition enter";
  gfx::Size scroll = render_view_->webview()->mainFrame()->scrollOffset();
  gfx::Rect rect = element_rect;
  rect.Offset(-scroll.width(), -scroll.height());
  render_view_->Send(new ViewHostMsg_SpeechInput_StartRecognition(
      render_view_->routing_id(), request_id, rect));
  VLOG(1) << "SpeechInputDispatcher::startRecognition exit";
  return true;
}

void SpeechInputDispatcher::cancelRecognition(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::cancelRecognition enter";
  render_view_->Send(new ViewHostMsg_SpeechInput_CancelRecognition(
      render_view_->routing_id(), request_id));
  VLOG(1) << "SpeechInputDispatcher::cancelRecognition exit";
}

void SpeechInputDispatcher::stopRecording(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::stopRecording enter";
  render_view_->Send(new ViewHostMsg_SpeechInput_StopRecording(
      render_view_->routing_id(), request_id));
  VLOG(1) << "SpeechInputDispatcher::stopRecording exit";
}

void SpeechInputDispatcher::OnSpeechRecognitionResult(
    int request_id, const string16& result) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionResult enter";
  WebKit::WebString webkit_result(result);
  listener_->setRecognitionResult(request_id, webkit_result);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionResult exit";
}

void SpeechInputDispatcher::OnSpeechRecordingComplete(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecordingComplete enter";
  listener_->didCompleteRecording(request_id);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecordingComplete exit";
}

void SpeechInputDispatcher::OnSpeechRecognitionComplete(int request_id) {
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionComplete enter";
  listener_->didCompleteRecognition(request_id);
  VLOG(1) << "SpeechInputDispatcher::OnSpeechRecognitionComplete exit";
}
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "storage/persistenttable.h"
#include "storage/ElasticScanner.h"

namespace voltdb
{
namespace elastic
{

/**
 * Constructor.
 */
Scanner::Scanner(PersistentTable &table) :
    m_table(table),
    m_blockMap(table.m_data),
    m_tupleSize(table.getTupleLength()),
    m_blockIterator(m_blockMap.begin()),
    m_blockEnd(m_blockMap.end()),
    m_currentBlockPtr(NULL),
    m_tuplePtr(NULL),
    m_tupleIndex(0)
{
}

/**
 * Internal method that handles transitions between blocks and
 * returns true as long as tuples are available.
 */
bool Scanner::continueScan() {
    bool hasMore = true;
    // First block or end of block?
    if (m_currentBlockPtr == NULL || m_tupleIndex >= m_currentBlockPtr->unusedTupleBoundry()) {
        // No more blocks?
        hasMore = (m_blockIterator != m_blockEnd);
        // Shift to the next block?
        if (hasMore) {
            m_tuplePtr = m_blockIterator.key();
            m_currentBlockPtr = m_blockIterator.data();
            assert(m_currentBlockPtr->address() == m_tuplePtr);
            m_blockIterator.data() = TBPtr();
            m_tupleIndex = 0;
            m_blockIterator++;
        }
    }
    return hasMore;
}

/**
 * Get the next tuple or return false if none is available.
 */
bool Scanner::next(TableTuple &out)
{
    bool found = false;
    while (!found && continueScan()) {
        assert(m_currentBlockPtr != NULL);
        // Sanity checks.
        assert(m_tuplePtr < m_currentBlockPtr.get()->address() + m_table.getTableAllocationSize());
        assert(m_tuplePtr < m_currentBlockPtr.get()->address() + (m_tupleSize * m_table.getTuplesPerBlock()));
        assert (out.sizeInValues() == m_table.columnCount());
        // Grab the tuple pointer.
        out.move(m_tuplePtr);
        // Shift to the next tuple in block.
        // continueScan() will check if it's the last one in the block.
        m_tupleIndex++;
        m_tuplePtr += m_tupleSize;
        // The next active/non-dirty tuple is return-worthy.
        found = out.isActive() && !out.isDirty();
    }
    return found;
}

/**
 * Block compaction hook.
 */
void Scanner::notifyBlockWasCompactedAway(TBPtr block) {
    if (m_blockIterator != m_blockEnd) {
        TBPtr nextBlock = m_blockIterator.data();
        if (nextBlock == block) {
            // The next block was compacted away.
            m_blockIterator++;
            if (m_blockIterator != m_blockEnd) {
                // There is a block to skip to.
                TBPtr newNextBlock = m_blockIterator.data();
                m_blockMap.erase(block->address());
                m_blockIterator = m_blockMap.find(newNextBlock->address());
                m_blockEnd = m_blockMap.end();
                assert(m_blockIterator != m_blockMap.end());
            }
            else {
                // There isn't a block to skip to, so we're done.
                m_blockMap.erase(block->address());
                m_blockIterator = m_blockMap.end();
                m_blockEnd = m_blockMap.end();
            }
        } else {
            // Some random block was compacted away.
            // Remove it and regenerate the iterator.
            m_blockMap.erase(block->address());
            m_blockIterator = m_blockMap.find(nextBlock->address());
            m_blockEnd = m_blockMap.end();
            assert(m_blockIterator != m_blockMap.end());
        }
    }
}

/**
 * Tuple insert hook.
 */
void Scanner::notifyTupleInsert(TableTuple &tuple) {
    // Nothing to do for insert. The caller will deal with it.
}

/**
 * Tuple update hook.
 */
void Scanner::notifyTupleUpdate(TableTuple &tuple) {
    // Nothing to do for update. The caller will deal with it.
}

} // namespace elastic
} // namespace voltdb<commit_msg>ENG-4536 Fixed missing EOL at EOF.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "storage/persistenttable.h"
#include "storage/ElasticScanner.h"

namespace voltdb
{
namespace elastic
{

/**
 * Constructor.
 */
Scanner::Scanner(PersistentTable &table) :
    m_table(table),
    m_blockMap(table.m_data),
    m_tupleSize(table.getTupleLength()),
    m_blockIterator(m_blockMap.begin()),
    m_blockEnd(m_blockMap.end()),
    m_currentBlockPtr(NULL),
    m_tuplePtr(NULL),
    m_tupleIndex(0)
{
}

/**
 * Internal method that handles transitions between blocks and
 * returns true as long as tuples are available.
 */
bool Scanner::continueScan() {
    bool hasMore = true;
    // First block or end of block?
    if (m_currentBlockPtr == NULL || m_tupleIndex >= m_currentBlockPtr->unusedTupleBoundry()) {
        // No more blocks?
        hasMore = (m_blockIterator != m_blockEnd);
        // Shift to the next block?
        if (hasMore) {
            m_tuplePtr = m_blockIterator.key();
            m_currentBlockPtr = m_blockIterator.data();
            assert(m_currentBlockPtr->address() == m_tuplePtr);
            m_blockIterator.data() = TBPtr();
            m_tupleIndex = 0;
            m_blockIterator++;
        }
    }
    return hasMore;
}

/**
 * Get the next tuple or return false if none is available.
 */
bool Scanner::next(TableTuple &out)
{
    bool found = false;
    while (!found && continueScan()) {
        assert(m_currentBlockPtr != NULL);
        // Sanity checks.
        assert(m_tuplePtr < m_currentBlockPtr.get()->address() + m_table.getTableAllocationSize());
        assert(m_tuplePtr < m_currentBlockPtr.get()->address() + (m_tupleSize * m_table.getTuplesPerBlock()));
        assert (out.sizeInValues() == m_table.columnCount());
        // Grab the tuple pointer.
        out.move(m_tuplePtr);
        // Shift to the next tuple in block.
        // continueScan() will check if it's the last one in the block.
        m_tupleIndex++;
        m_tuplePtr += m_tupleSize;
        // The next active/non-dirty tuple is return-worthy.
        found = out.isActive() && !out.isDirty();
    }
    return found;
}

/**
 * Block compaction hook.
 */
void Scanner::notifyBlockWasCompactedAway(TBPtr block) {
    if (m_blockIterator != m_blockEnd) {
        TBPtr nextBlock = m_blockIterator.data();
        if (nextBlock == block) {
            // The next block was compacted away.
            m_blockIterator++;
            if (m_blockIterator != m_blockEnd) {
                // There is a block to skip to.
                TBPtr newNextBlock = m_blockIterator.data();
                m_blockMap.erase(block->address());
                m_blockIterator = m_blockMap.find(newNextBlock->address());
                m_blockEnd = m_blockMap.end();
                assert(m_blockIterator != m_blockMap.end());
            }
            else {
                // There isn't a block to skip to, so we're done.
                m_blockMap.erase(block->address());
                m_blockIterator = m_blockMap.end();
                m_blockEnd = m_blockMap.end();
            }
        } else {
            // Some random block was compacted away.
            // Remove it and regenerate the iterator.
            m_blockMap.erase(block->address());
            m_blockIterator = m_blockMap.find(nextBlock->address());
            m_blockEnd = m_blockMap.end();
            assert(m_blockIterator != m_blockMap.end());
        }
    }
}

/**
 * Tuple insert hook.
 */
void Scanner::notifyTupleInsert(TableTuple &tuple) {
    // Nothing to do for insert. The caller will deal with it.
}

/**
 * Tuple update hook.
 */
void Scanner::notifyTupleUpdate(TableTuple &tuple) {
    // Nothing to do for update. The caller will deal with it.
}

} // namespace elastic
} // namespace voltdb
<|endoftext|>