<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * e133-receiver.cpp
 * Copyright (C) 2011 Simon Newton
 *
 * This creates a E1.33 receiver with one (emulated) RDM responder. The node is
 * registered in slp and the RDM responder responds to E1.33 commands.
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <signal.h>
#include <sysexits.h>

#include <ola/acn/ACNPort.h>
#include <ola/acn/CID.h>
#include <ola/DmxBuffer.h>
#include <ola/base/Flags.h>
#include <ola/base/Init.h>
#include <ola/BaseTypes.h>
#include <ola/io/Descriptor.h>
#include <ola/Logging.h>
#include <ola/network/InterfacePicker.h>
#include <ola/rdm/RDMControllerAdaptor.h>
#include <ola/rdm/UIDAllocator.h>
#include <ola/rdm/UID.h>
#include <ola/stl/STLUtils.h>

#include <memory>
#include <string>
#include <vector>

#ifdef USE_SPI
#include "plugins/spi/SPIBackend.h"
using ola::plugin::spi::SPIBackend;
DEFINE_string(spi_device, "", "Path to the SPI device to use.");
#endif

#include "plugins/e131/e131/E131Node.h"
#include "plugins/usbpro/BaseUsbProWidget.h"
#include "plugins/usbpro/DmxTriWidget.h"
#include "tools/e133/SimpleE133Node.h"

using ola::DmxBuffer;
using ola::acn::CID;
using ola::network::IPV4Address;
using ola::rdm::UID;
using std::auto_ptr;
using std::string;
using std::vector;
using ola::plugin::usbpro::DmxTriWidget;

DEFINE_bool(dummy, true, "Include a dummy responder endpoint");
DEFINE_bool(e131, true, "Include E1.31 support");
DEFINE_string(listen_ip, "", "The IP address to listen on.");
DEFINE_string(uid, "7a70:00000001", "The UID of the responder.");
DEFINE_s_uint16(lifetime, t, 300, "The value to use for the service lifetime");
DEFINE_s_uint32(universe, u, 1, "The E1.31 universe to listen on.");
DEFINE_string(tri_device, "", "Path to the RDM-TRI device to use.");

SimpleE133Node *simple_node;

/*
 * Terminate cleanly on interrupt.
 */
static void InteruptSignal(int signo) {
  if (simple_node)
    simple_node->Stop();
  (void) signo;
}

void HandleDMX(DmxBuffer *buffer, DmxTriWidget *widget) {
  widget->SendDMX(*buffer);
}

#ifdef USE_SPI
void HandleDMX(DmxBuffer *buffer, SPIBackend *backend) {
  backend->WriteDMX(*buffer, 0);
}
#endif

/*
 * Startup a node
 */
int main(int argc, char *argv[]) {
  ola::SetHelpString(
      "[options]",
      "Run a very simple E1.33 Responder.");
  ola::ParseFlags(&argc, argv);
  ola::InitLoggingFromFlags();

  auto_ptr<UID> uid(UID::FromString(FLAGS_uid));
  if (!uid.get()) {
    OLA_WARN << "Invalid UID: " << FLAGS_uid;
    ola::DisplayUsage();
    exit(EX_USAGE);
  }

  CID cid = CID::Generate();

  // Find a network interface to use
  ola::network::Interface interface;

  {
    auto_ptr<const ola::network::InterfacePicker> picker(
      ola::network::InterfacePicker::NewPicker());
    if (!picker->ChooseInterface(&interface, FLAGS_listen_ip)) {
      OLA_INFO << "Failed to find an interface";
      exit(EX_UNAVAILABLE);
    }
  }

  // Setup the Node.
  SimpleE133Node::Options opts(cid, interface.ip_address, *uid, FLAGS_lifetime);
  SimpleE133Node node(opts);

  // Optionally attach some other endpoints.
  vector<E133Endpoint*> endpoints;
  auto_ptr<ola::plugin::dummy::DummyResponder> dummy_responder;
  auto_ptr<ola::rdm::DiscoverableRDMControllerAdaptor>
    discoverable_dummy_responder;
  auto_ptr<DmxTriWidget> tri_widget;

  ola::rdm::UIDAllocator uid_allocator(*uid);
  // The first uid is used for the management endpoint so we burn a UID here.
  {
    auto_ptr<UID> dummy_uid(uid_allocator.AllocateNext());
  }

  // Setup E1.31 if required.
  auto_ptr<ola::plugin::e131::E131Node> e131_node;
  if (FLAGS_e131) {
    e131_node.reset(new ola::plugin::e131::E131Node(FLAGS_listen_ip, cid));
    if (!e131_node->Start()) {
      OLA_WARN << "Failed to start E1.31 node";
      exit(EX_UNAVAILABLE);
    }
    OLA_INFO << "Started E1.31 node!";
    node.SelectServer()->AddReadDescriptor(e131_node->GetSocket());
  }

  if (FLAGS_dummy) {
    auto_ptr<UID> dummy_uid(uid_allocator.AllocateNext());
    if (!dummy_uid.get()) {
      OLA_WARN << "Failed to allocate a UID for the DummyResponder.";
      exit(EX_USAGE);
    }

    dummy_responder.reset(new ola::plugin::dummy::DummyResponder(*dummy_uid));
    discoverable_dummy_responder.reset(
        new ola::rdm::DiscoverableRDMControllerAdaptor(
          *dummy_uid, dummy_responder.get()));
    endpoints.push_back(new E133Endpoint(discoverable_dummy_responder.get(),
                                         E133Endpoint::EndpointProperties()));
  }

  // uber hack for now.
  // TODO(simon): fix this
  DmxBuffer tri_buffer;
  uint8_t unused_priority;
  if (!FLAGS_tri_device.str().empty()) {
    ola::io::ConnectedDescriptor *descriptor =
        ola::plugin::usbpro::BaseUsbProWidget::OpenDevice(FLAGS_tri_device);
    if (!descriptor) {
      OLA_WARN << "Failed to open " << FLAGS_tri_device;
      exit(EX_USAGE);
    }
    tri_widget.reset(new DmxTriWidget(node.SelectServer(), descriptor));
    node.SelectServer()->AddReadDescriptor(descriptor);
    E133Endpoint::EndpointProperties properties;
    properties.is_physical = true;
    endpoints.push_back(
        new E133Endpoint(tri_widget.get(), properties));

    if (e131_node.get()) {
      // Danger!
      e131_node->SetHandler(
          1, &tri_buffer, &unused_priority,
          NewCallback(&HandleDMX, &tri_buffer, tri_widget.get()));
    }
  }

  // uber hack for now.
  // TODO(simon): fix this
#ifdef USE_SPI
  auto_ptr<SPIBackend> spi_backend;
  DmxBuffer spi_buffer;

  if (!FLAGS_spi_device.str().empty()) {
    auto_ptr<UID> spi_uid(uid_allocator.AllocateNext());
    if (!spi_uid.get()) {
      OLA_WARN << "Failed to allocate a UID for the SPI device.";
      exit(EX_USAGE);
    }

    spi_backend.reset(
        new SPIBackend(FLAGS_spi_device, *spi_uid, SPIBackend::Options()));
    E133Endpoint::EndpointProperties properties;
    properties.is_physical = true;
    endpoints.push_back(new E133Endpoint(spi_backend.get(), properties));

    if (e131_node.get()) {
      // Danger!
      e131_node->SetHandler(
          1, &spi_buffer, &unused_priority,
          NewCallback(&HandleDMX, &spi_buffer, spi_backend.get()));
    }
  }
#endif

  for (unsigned int i = 0; i < endpoints.size(); i++) {
    node.AddEndpoint(i + 1, endpoints[i]);
  }
  simple_node = &node;

  if (!node.Init())
    exit(EX_UNAVAILABLE);

  // signal handler
  if (!ola::InstallSignal(SIGINT, &InteruptSignal))
    return false;

  node.Run();
  if (e131_node.get()) {
    node.SelectServer()->RemoveReadDescriptor(e131_node->GetSocket());
  }
  for (unsigned int i = 0; i < endpoints.size(); i++) {
    node.RemoveEndpoint(i + 1);
  }
  ola::STLDeleteElements(&endpoints);
}
<commit_msg>* make the function names unique<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * e133-receiver.cpp
 * Copyright (C) 2011 Simon Newton
 *
 * This creates a E1.33 receiver with one (emulated) RDM responder. The node is
 * registered in slp and the RDM responder responds to E1.33 commands.
 */

#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <signal.h>
#include <sysexits.h>

#include <ola/acn/ACNPort.h>
#include <ola/acn/CID.h>
#include <ola/DmxBuffer.h>
#include <ola/base/Flags.h>
#include <ola/base/Init.h>
#include <ola/BaseTypes.h>
#include <ola/io/Descriptor.h>
#include <ola/Logging.h>
#include <ola/network/InterfacePicker.h>
#include <ola/rdm/RDMControllerAdaptor.h>
#include <ola/rdm/UIDAllocator.h>
#include <ola/rdm/UID.h>
#include <ola/stl/STLUtils.h>

#include <memory>
#include <string>
#include <vector>

#ifdef USE_SPI
#include "plugins/spi/SPIBackend.h"
using ola::plugin::spi::SPIBackend;
DEFINE_string(spi_device, "", "Path to the SPI device to use.");
#endif

#include "plugins/e131/e131/E131Node.h"
#include "plugins/usbpro/BaseUsbProWidget.h"
#include "plugins/usbpro/DmxTriWidget.h"
#include "tools/e133/SimpleE133Node.h"

using ola::DmxBuffer;
using ola::acn::CID;
using ola::network::IPV4Address;
using ola::rdm::UID;
using std::auto_ptr;
using std::string;
using std::vector;
using ola::plugin::usbpro::DmxTriWidget;

DEFINE_bool(dummy, true, "Include a dummy responder endpoint");
DEFINE_bool(e131, true, "Include E1.31 support");
DEFINE_string(listen_ip, "", "The IP address to listen on.");
DEFINE_string(uid, "7a70:00000001", "The UID of the responder.");
DEFINE_s_uint16(lifetime, t, 300, "The value to use for the service lifetime");
DEFINE_s_uint32(universe, u, 1, "The E1.31 universe to listen on.");
DEFINE_string(tri_device, "", "Path to the RDM-TRI device to use.");

SimpleE133Node *simple_node;

/*
 * Terminate cleanly on interrupt.
 */
static void InteruptSignal(int signo) {
  if (simple_node)
    simple_node->Stop();
  (void) signo;
}

void HandleTriDMX(DmxBuffer *buffer, DmxTriWidget *widget) {
  widget->SendDMX(*buffer);
}

#ifdef USE_SPI
void HandleSpiDMX(DmxBuffer *buffer, SPIBackend *backend) {
  backend->WriteDMX(*buffer, 0);
}
#endif

/*
 * Startup a node
 */
int main(int argc, char *argv[]) {
  ola::SetHelpString(
      "[options]",
      "Run a very simple E1.33 Responder.");
  ola::ParseFlags(&argc, argv);
  ola::InitLoggingFromFlags();

  auto_ptr<UID> uid(UID::FromString(FLAGS_uid));
  if (!uid.get()) {
    OLA_WARN << "Invalid UID: " << FLAGS_uid;
    ola::DisplayUsage();
    exit(EX_USAGE);
  }

  CID cid = CID::Generate();

  // Find a network interface to use
  ola::network::Interface interface;

  {
    auto_ptr<const ola::network::InterfacePicker> picker(
      ola::network::InterfacePicker::NewPicker());
    if (!picker->ChooseInterface(&interface, FLAGS_listen_ip)) {
      OLA_INFO << "Failed to find an interface";
      exit(EX_UNAVAILABLE);
    }
  }

  // Setup the Node.
  SimpleE133Node::Options opts(cid, interface.ip_address, *uid, FLAGS_lifetime);
  SimpleE133Node node(opts);

  // Optionally attach some other endpoints.
  vector<E133Endpoint*> endpoints;
  auto_ptr<ola::plugin::dummy::DummyResponder> dummy_responder;
  auto_ptr<ola::rdm::DiscoverableRDMControllerAdaptor>
    discoverable_dummy_responder;
  auto_ptr<DmxTriWidget> tri_widget;

  ola::rdm::UIDAllocator uid_allocator(*uid);
  // The first uid is used for the management endpoint so we burn a UID here.
  {
    auto_ptr<UID> dummy_uid(uid_allocator.AllocateNext());
  }

  // Setup E1.31 if required.
  auto_ptr<ola::plugin::e131::E131Node> e131_node;
  if (FLAGS_e131) {
    e131_node.reset(new ola::plugin::e131::E131Node(FLAGS_listen_ip, cid));
    if (!e131_node->Start()) {
      OLA_WARN << "Failed to start E1.31 node";
      exit(EX_UNAVAILABLE);
    }
    OLA_INFO << "Started E1.31 node!";
    node.SelectServer()->AddReadDescriptor(e131_node->GetSocket());
  }

  if (FLAGS_dummy) {
    auto_ptr<UID> dummy_uid(uid_allocator.AllocateNext());
    if (!dummy_uid.get()) {
      OLA_WARN << "Failed to allocate a UID for the DummyResponder.";
      exit(EX_USAGE);
    }

    dummy_responder.reset(new ola::plugin::dummy::DummyResponder(*dummy_uid));
    discoverable_dummy_responder.reset(
        new ola::rdm::DiscoverableRDMControllerAdaptor(
          *dummy_uid, dummy_responder.get()));
    endpoints.push_back(new E133Endpoint(discoverable_dummy_responder.get(),
                                         E133Endpoint::EndpointProperties()));
  }

  // uber hack for now.
  // TODO(simon): fix this
  DmxBuffer tri_buffer;
  uint8_t unused_priority;
  if (!FLAGS_tri_device.str().empty()) {
    ola::io::ConnectedDescriptor *descriptor =
        ola::plugin::usbpro::BaseUsbProWidget::OpenDevice(FLAGS_tri_device);
    if (!descriptor) {
      OLA_WARN << "Failed to open " << FLAGS_tri_device;
      exit(EX_USAGE);
    }
    tri_widget.reset(new DmxTriWidget(node.SelectServer(), descriptor));
    node.SelectServer()->AddReadDescriptor(descriptor);
    E133Endpoint::EndpointProperties properties;
    properties.is_physical = true;
    endpoints.push_back(
        new E133Endpoint(tri_widget.get(), properties));

    if (e131_node.get()) {
      // Danger!
      e131_node->SetHandler(
          1, &tri_buffer, &unused_priority,
          NewCallback(&HandleTriDMX, &tri_buffer, tri_widget.get()));
    }
  }

  // uber hack for now.
  // TODO(simon): fix this
#ifdef USE_SPI
  auto_ptr<SPIBackend> spi_backend;
  DmxBuffer spi_buffer;

  if (!FLAGS_spi_device.str().empty()) {
    auto_ptr<UID> spi_uid(uid_allocator.AllocateNext());
    if (!spi_uid.get()) {
      OLA_WARN << "Failed to allocate a UID for the SPI device.";
      exit(EX_USAGE);
    }

    spi_backend.reset(
        new SPIBackend(FLAGS_spi_device, *spi_uid, SPIBackend::Options()));
    E133Endpoint::EndpointProperties properties;
    properties.is_physical = true;
    endpoints.push_back(new E133Endpoint(spi_backend.get(), properties));

    if (e131_node.get()) {
      // Danger!
      e131_node->SetHandler(
          1, &spi_buffer, &unused_priority,
          NewCallback(&HandleSpiDMX, &spi_buffer, spi_backend.get()));
    }
  }
#endif

  for (unsigned int i = 0; i < endpoints.size(); i++) {
    node.AddEndpoint(i + 1, endpoints[i]);
  }
  simple_node = &node;

  if (!node.Init())
    exit(EX_UNAVAILABLE);

  // signal handler
  if (!ola::InstallSignal(SIGINT, &InteruptSignal))
    return false;

  node.Run();
  if (e131_node.get()) {
    node.SelectServer()->RemoveReadDescriptor(e131_node->GetSocket());
  }
  for (unsigned int i = 0; i < endpoints.size(); i++) {
    node.RemoveEndpoint(i + 1);
  }
  ola::STLDeleteElements(&endpoints);
}
<|endoftext|>


<commit_before>#include "Spectrum2.h"

Spectrum2::Spectrum2(uint16_t columns,
  uint16_t rows,
  uint16_t rowOffset,
  uint16_t length,
  uint8_t hue,
  uint8_t saturation,
  bool invert,
  CRGB * leds)
: Visualization(columns, rows, hue, saturation, leds) {
  this->rowOffset = rowOffset;
  this->invert = invert;
  this->length = length;
  this->density = 0.06;
  this->threshold = 1000.0;
  this->peak = 2000.0;
  this->drift = 0;
  this->totalMagnitudeMovingAverage = 20000.0;
}

void Spectrum2::display(float* magnitudes) {
  uint_fast16_t peakCount = 0;
  bool overPeak = false;

  float sorted[this->length];
  memcpy(sorted, magnitudes, sizeof(magnitudes[0]) * this->length);
  std::sort(sorted, sorted+sizeof(sorted)/sizeof(sorted[0]));

  const float alpha = 0.9;

  float cutoffMagnitude = sorted[(uint_fast16_t)((1 - this->density)*this->length)];
  float peakMagnitude = sorted[this->length - 2];
  this->threshold = (this->threshold * alpha) + (cutoffMagnitude* (1 - alpha));
  this->peak = (this->peak * alpha) + (peakMagnitude * (1 - alpha));

  float magnitude;
  float magnitudeSum = 0;

  for (uint8_t y=0; y<this->length; y++) {
    overPeak = false;
    magnitudeSum += magnitudes[y];

    if (magnitudes[y] < this->threshold) {
      continue;
    }

    if (magnitudes[y] > this->peak * 1.2) {
      peakCount++;
      overPeak = true;
    }

    magnitude = ((magnitudes[y] - this->threshold) / (this->peak - this->threshold));
    magnitude = min(magnitude, 1);
    magnitude = max(magnitude, 0.15);

    CRGB c = CHSV(this->hue, this->saturation, magnitude*255);
    CRGB c2 = CHSV(this->hue, this->saturation, magnitude*128);
    for (uint8_t x=0; x<this->columns; x++) {
      if (this->invert) {
        leds[this->xy2Pos(x, this->rowOffset - y)] = c;
        if (overPeak) {
          if (y > 0) {
            leds[this->xy2Pos(x, (this->rowOffset - (y - 1)))] = c2;
          }
          if (y < this->length - 1) {
            leds[this->xy2Pos(x, (this->rowOffset - (y + 1)))] = c2;
          }
        }
      } else {
        leds[this->xy2Pos(x, y + this->rowOffset)] = c;
        if (overPeak) {
          if (y > 0) {
            leds[this->xy2Pos(x, (y + this->rowOffset) - 1)] = c2;
          }
          if (y < this->length - 1) {
            leds[this->xy2Pos(x, y + this->rowOffset + 1)] = c2;
          }
        }
      }
    }
    if (overPeak) {
      y++;
    }
  }

  this->hue += this->drift;

  // Change hue to pink on big volume increases
  if (this->drift > 0 && magnitudeSum > this->totalMagnitudeMovingAverage * 1.75) {
    this->hue = 240;
  }

  this->totalMagnitudeMovingAverage = (this->totalMagnitudeMovingAverage * (0.9998)) + (magnitudeSum/5000.0);

  uint_fast32_t currentTime = millis();

  // put things we want to log here
  if (currentTime > this->loggingTimestamp + 5000) {
    this->loggingTimestamp = currentTime;

    // Serial.print(peakCount);
    // Serial.print(cutoffMagnitude);
    // Serial.print("\t");
    // Serial.print(peakMagnitude);
    // Serial.print("\t");
    // Serial.print(this->threshold);
    // Serial.print("\t");
    // Serial.print(this->peak);
    // Serial.print("\t");
    // Serial.print(this->hue);
    // Serial.print("\t");
    // Serial.print(magnitudeSum);
    // Serial.print("\t");
    // Serial.print(this->totalMagnitudeMovingAverage);
    // Serial.println("");
  }
}

void Spectrum2::setDrift(uint8_t drift) {
  this->drift = drift;
}

float Spectrum2::getDensity() {
  return this->density;
}

void Spectrum2::setDensity(float density) {
  this->density = density;
}
<commit_msg>make drift time based vs cycle based<commit_after>#include "Spectrum2.h"

Spectrum2::Spectrum2(uint16_t columns,
  uint16_t rows,
  uint16_t rowOffset,
  uint16_t length,
  uint8_t hue,
  uint8_t saturation,
  bool invert,
  CRGB * leds)
: Visualization(columns, rows, hue, saturation, leds) {
  this->rowOffset = rowOffset;
  this->invert = invert;
  this->length = length;
  this->density = 0.06;
  this->threshold = 1000.0;
  this->peak = 2000.0;
  this->drift = 0;
  this->totalMagnitudeMovingAverage = 20000.0;
}

void Spectrum2::display(float* magnitudes) {
  uint_fast16_t peakCount = 0;
  bool overPeak = false;

  float sorted[this->length];
  memcpy(sorted, magnitudes, sizeof(magnitudes[0]) * this->length);
  std::sort(sorted, sorted+sizeof(sorted)/sizeof(sorted[0]));

  const float alpha = 0.9;

  float cutoffMagnitude = sorted[(uint_fast16_t)((1 - this->density)*this->length)];
  float peakMagnitude = sorted[this->length - 2];
  this->threshold = (this->threshold * alpha) + (cutoffMagnitude* (1 - alpha));
  this->peak = (this->peak * alpha) + (peakMagnitude * (1 - alpha));

  float magnitude;
  float magnitudeSum = 0;

  for (uint8_t y=0; y<this->length; y++) {
    overPeak = false;
    magnitudeSum += magnitudes[y];

    if (magnitudes[y] < this->threshold) {
      continue;
    }

    if (magnitudes[y] > this->peak * 1.2) {
      peakCount++;
      overPeak = true;
    }

    magnitude = ((magnitudes[y] - this->threshold) / (this->peak - this->threshold));
    magnitude = min(magnitude, 1);
    magnitude = max(magnitude, 0.15);

    CRGB c = CHSV(this->hue, this->saturation, magnitude*255);
    CRGB c2 = CHSV(this->hue, this->saturation, magnitude*128);
    for (uint8_t x=0; x<this->columns; x++) {
      if (this->invert) {
        leds[this->xy2Pos(x, this->rowOffset - y)] = c;
        if (overPeak) {
          if (y > 0) {
            leds[this->xy2Pos(x, (this->rowOffset - (y - 1)))] = c2;
          }
          if (y < this->length - 1) {
            leds[this->xy2Pos(x, (this->rowOffset - (y + 1)))] = c2;
          }
        }
      } else {
        leds[this->xy2Pos(x, y + this->rowOffset)] = c;
        if (overPeak) {
          if (y > 0) {
            leds[this->xy2Pos(x, (y + this->rowOffset) - 1)] = c2;
          }
          if (y < this->length - 1) {
            leds[this->xy2Pos(x, y + this->rowOffset + 1)] = c2;
          }
        }
      }
    }
    if (overPeak) {
      y++;
    }
  }

  uint_fast32_t currentTime = millis();

  this->hue = (currentTime / this->drift) % 256;

  // Change hue to pink on big volume increases
  if (this->drift > 0 && magnitudeSum > this->totalMagnitudeMovingAverage * 1.75) {
    this->hue = 240;
  }

  this->totalMagnitudeMovingAverage = (this->totalMagnitudeMovingAverage * (0.9998)) + (magnitudeSum/5000.0);

  // put things we want to log here
  if (currentTime > this->loggingTimestamp + 5000) {
    this->loggingTimestamp = currentTime;

    // Serial.print(peakCount);
    // Serial.print(cutoffMagnitude);
    // Serial.print("\t");
    // Serial.print(peakMagnitude);
    // Serial.print("\t");
    // Serial.print(this->threshold);
    // Serial.print("\t");
    // Serial.print(this->peak);
    // Serial.print("\t");
    // Serial.print(this->hue);
    // Serial.print("\t");
    // Serial.print(magnitudeSum);
    // Serial.print("\t");
    // Serial.print(this->totalMagnitudeMovingAverage);
    // Serial.println("");
  }
}

void Spectrum2::setDrift(uint8_t drift) {
  this->drift = drift;
}

float Spectrum2::getDensity() {
  return this->density;
}

void Spectrum2::setDensity(float density) {
  this->density = density;
}
<|endoftext|>


<commit_before>/*
** Copyright 2015 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** For more information : contact@centreon.com
*/

#include <sstream>
#include "com/centreon/broker/database.hh"
#include "com/centreon/broker/database_preparator.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/mapping/entry.hh"

using namespace com::centreon::broker;

/**
 *  Constructor.
 *
 *  @param[in] event_id  Event ID.
 *  @param[in] unique    Event UNIQUE.
 *  @param[in] excluded  Fields excluded from the query.
 */
database_preparator::database_preparator(
                       unsigned int event_id,
                       database_preparator::event_unique const& unique,
                       database_query::excluded_fields const& excluded)
  : _event_id(event_id), _excluded(excluded), _unique(unique) {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
database_preparator::database_preparator(
                       database_preparator const& other) {
  _event_id = other._event_id;
  _excluded = other._excluded;
  _unique = other._unique;
}

/**
 *  Destructor.
 */
database_preparator::~database_preparator() {}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
database_preparator& database_preparator::operator=(
                       database_preparator const& other) {
  if (this != &other) {
    _event_id = other._event_id;
    _excluded = other._excluded;
    _unique = other._unique;
  }
  return (*this);
}

/**
 *  Prepare insertion query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_insert(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare insertion query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Build query string.
  std::string query;
  query = "INSERT INTO ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" (");
  mapping::entry const* entries(info->get_mapping());
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    query.append(entry_name);
    query.append(", ");
  }
  query.resize(query.size() - 2);
  query.append(") VALUES(");
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    query.append(":");
    query.append(entry_name);
    query.append(", ");
  }
  query.resize(query.size() - 2);
  query.append(")");

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare insertion query for event '"
           << info->get_name() << "' in table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}

/**
 *  Prepare update query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_update(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare update query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Build query string.
  std::string query;
  std::string where;
  query = "UPDATE ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" SET ");
  where = " WHERE ";
  mapping::entry const* entries(info->get_mapping());
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    // Standard field.
    if (_unique.find(entry_name) == _unique.end()) {
      query.append(entry_name);
      query.append("=:");
      query.append(entry_name);
      query.append(", ");
    }
    // Part of ID field.
    else {
      where.append("COALESCE(");
      where.append(entry_name);
      where.append(", -1)=COALESCE(:");
      where.append(entry_name);
      where.append(", -1) AND ");
    }
  }
  query.resize(query.size() - 2);
  query.append(where, 0, where.size() - 5);

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare update query for event '"
           << info->get_name() << "' on table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}

/**
 *  Prepare deletion query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_delete(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare deletion query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Prepare query.
  std::string query;
  query = "DELETE FROM ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" WHERE ");
  for (event_unique::const_iterator
         it(_unique.begin()),
         end(_unique.end());
       it != end;
       ++it) {
    query.append("COALESCE(");
    query.append(*it);
    query.append(", -1)=COALESCE(:");
    query.append(*it);
    query.append(", -1) AND ");
  }
  query.resize(query.size() - 5);

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare deletion query for event '"
           << info->get_name() << "' on table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}
<commit_msg>Core: fix indexing in database preparator queries.<commit_after>/*
** Copyright 2015 Centreon
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**
** For more information : contact@centreon.com
*/

#include <sstream>
#include "com/centreon/broker/database.hh"
#include "com/centreon/broker/database_preparator.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/mapping/entry.hh"

using namespace com::centreon::broker;

/**
 *  Constructor.
 *
 *  @param[in] event_id  Event ID.
 *  @param[in] unique    Event UNIQUE.
 *  @param[in] excluded  Fields excluded from the query.
 */
database_preparator::database_preparator(
                       unsigned int event_id,
                       database_preparator::event_unique const& unique,
                       database_query::excluded_fields const& excluded)
  : _event_id(event_id), _excluded(excluded), _unique(unique) {}

/**
 *  Copy constructor.
 *
 *  @param[in] other  Object to copy.
 */
database_preparator::database_preparator(
                       database_preparator const& other) {
  _event_id = other._event_id;
  _excluded = other._excluded;
  _unique = other._unique;
}

/**
 *  Destructor.
 */
database_preparator::~database_preparator() {}

/**
 *  Assignment operator.
 *
 *  @param[in] other  Object to copy.
 *
 *  @return This object.
 */
database_preparator& database_preparator::operator=(
                       database_preparator const& other) {
  if (this != &other) {
    _event_id = other._event_id;
    _excluded = other._excluded;
    _unique = other._unique;
  }
  return (*this);
}

/**
 *  Prepare insertion query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_insert(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare insertion query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Build query string.
  std::string query;
  query = "INSERT INTO ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" (");
  mapping::entry const* entries(info->get_mapping());
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    query.append(entry_name);
    query.append(", ");
  }
  query.resize(query.size() - 2);
  query.append(") VALUES(");
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    query.append(":");
    query.append(entry_name);
    query.append(", ");
  }
  query.resize(query.size() - 2);
  query.append(")");

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare insertion query for event '"
           << info->get_name() << "' in table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}

/**
 *  Prepare update query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_update(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare update query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Build query string.
  std::string query;
  std::string where;
  query = "UPDATE ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" SET ");
  where = " WHERE ";
  mapping::entry const* entries(info->get_mapping());
  for (int i(0); !entries[i].is_null(); ++i) {
    char const* entry_name;
    if (schema_v2)
      entry_name = entries[i].get_name_v2();
    else
      entry_name = entries[i].get_name();
    if (!entry_name
        || !entry_name[0]
        || (_excluded.find(entry_name) != _excluded.end()))
      continue ;
    // Standard field.
    if (_unique.find(entry_name) == _unique.end()) {
      query.append(entry_name);
      query.append("=:");
      query.append(entry_name);
      query.append(", ");
    }
    // Part of ID field.
    else {
      where.append(entry_name);
      where.append("=COALESCE(:");
      where.append(entry_name);
      where.append(", -1) AND ");
    }
  }
  query.resize(query.size() - 2);
  query.append(where, 0, where.size() - 5);

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare update query for event '"
           << info->get_name() << "' on table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}

/**
 *  Prepare deletion query for specified event.
 *
 *  @param[out] q  Database query, prepared and ready to run.
 */
void database_preparator::prepare_delete(database_query& q) {
  // Find event info.
  io::event_info const*
    info(io::events::instance().get_event_info(_event_id));
  if (!info)
    throw (exceptions::msg()
           << "could not prepare deletion query for event of type "
           << _event_id << ": event is not registered");

  // Database schema version.
  bool schema_v2(q.db_object().schema_version() == database::v2);

  // Prepare query.
  std::string query;
  query = "DELETE FROM ";
  if (schema_v2)
    query.append(info->get_table_v2());
  else
    query.append(info->get_table());
  query.append(" WHERE ");
  for (event_unique::const_iterator
         it(_unique.begin()),
         end(_unique.end());
       it != end;
       ++it) {
    query.append(*it);
    query.append("=COALESCE(:");
    query.append(*it);
    query.append(", -1) AND ");
  }
  query.resize(query.size() - 5);

  // Prepare statement.
  try {
    q.prepare(query);
  }
  catch (std::exception const& e) {
    throw (exceptions::msg()
           << "could not prepare deletion query for event '"
           << info->get_name() << "' on table '"
           << info->get_table() << "': " << e.what());
  }

  return ;
}
<|endoftext|>


<commit_before>#include "styleContext.h"
#include "platform.h"
#include "builders.h"
#include "scene/scene.h"

#define DUMP(...) //do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)

namespace Tangram {

const static char DATA_ID[] = "\xff""\xff""data";
const static char ATTR_ID[] = "\xff""\xff""attr";
const static char FUNC_ID[] = "\xff""\xff""fns";

StyleContext::StyleContext() {
    m_ctx = duk_create_heap_default();

    // add empty feature_object
    duk_push_object(m_ctx);

    // assign instance to feature_object
    duk_push_pointer(m_ctx, this);
    if (!duk_put_prop_string(m_ctx, -2, DATA_ID)) {
        LOGE("Ctx not assigned");
    }

    // put object in global scope
    if (!duk_put_global_string(m_ctx, "feature")) {
        LOGE("Feature not assigned");
    }

    DUMP("init\n");
}

StyleContext::~StyleContext() {
    duk_destroy_heap(m_ctx);
}

void StyleContext::initFunctions(const Scene& _scene) {

    if (_scene.id == m_sceneId) {
        return;
    }
    m_sceneId = _scene.id;

    auto arr_idx = duk_push_array(m_ctx);
    int id = 0;

    for (auto& function : _scene.functions()) {
        LOGD("compile '%s'", function.c_str());
        duk_push_string(m_ctx, function.c_str());
        duk_push_string(m_ctx, "");

        if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) == 0) {
            duk_put_prop_index(m_ctx, arr_idx, id);
        } else {
            LOGE("Compile failed: %s", duk_safe_to_string(m_ctx, -1));
            duk_pop(m_ctx);
        }
        id++;
    }

    if (!duk_put_global_string(m_ctx, FUNC_ID)) {
        LOGE("'fns' object not set");
    }

    DUMP("setScene - %d functions\n", id);
}

void StyleContext::setFeature(const Feature& _feature) {
    m_feature = &_feature;

    for (auto& item : _feature.props.items()) {
        addAccessor(item.key);
    }
}

void StyleContext::setGlobalZoom(float _zoom) {
    static const std::string _key("$zoom");
    if (_zoom != m_globalZoom) {
        setGlobal(_key, _zoom);
    }
}

void StyleContext::setGlobal(const std::string& _key, const Value& _val) {
    Value& entry = m_globals[_key];
    if (entry == _val) { return; }

    entry = _val;

    if (_val.is<float>()) {
        duk_push_number(m_ctx, _val.get<float>());
        duk_put_global_string(m_ctx, _key.c_str());

        if (_key == "$zoom") { m_globalZoom = _val.get<float>(); }

    } else if (_val.is<std::string>()) {
        duk_push_string(m_ctx, _val.get<std::string>().c_str());
        duk_put_global_string(m_ctx, _key.c_str());
    }
}

const Value& StyleContext::getGlobal(const std::string& _key) const {

    const static Value NOT_FOUND(none_type{});

    auto it = m_globals.find(_key);
    if (it != m_globals.end()) {
        return it->second;
    }
    return NOT_FOUND;
}

void StyleContext::clear() {
    m_feature = nullptr;
}

bool StyleContext::addFunction(const std::string& _name, const std::string& _func) {

    duk_push_string(m_ctx, _func.c_str());
    duk_push_string(m_ctx, _name.c_str());

    if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) != 0) {
        LOGE("Compile failed: %s", duk_safe_to_string(m_ctx, -1));
        return false;
    }

    // Put function in global scope
    duk_put_global_string(m_ctx, _name.c_str());

    DUMP("addFunction\n");
    return true;
}

bool StyleContext::evalFilter(FunctionID _id) const {
    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
        LOGE("EvalFilterFn - functions not initialized");
        return false;
    }

    if (!duk_get_prop_index(m_ctx, -1, _id)) {
        LOGE("EvalFilterFn - function %d not set", _id);
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
    }

    bool result = false;

    if (duk_is_boolean(m_ctx, -1)) {
        result = duk_get_boolean(m_ctx, -1);
    }

    // pop result
    duk_pop(m_ctx);
    // pop fns obj
    duk_pop(m_ctx);

    DUMP("evalFilterFn\n");
    return result;
}

bool StyleContext::evalFilterFn(const std::string& _name) {
    if (!duk_get_global_string(m_ctx, _name.c_str())) {
        LOGE("EvalFilter %s", _name.c_str());
        return false;
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
    }

    bool result = false;

    if (duk_is_boolean(m_ctx, -1)) {
        result = duk_get_boolean(m_ctx, -1);
    }

    // pop result
    duk_pop(m_ctx);

    DUMP("evalFilterFn\n");
    return result;
}

bool StyleContext::parseStyleResult(StyleParamKey _key, StyleParam::Value& _val) const {
    _val = none_type{};

    if (duk_is_string(m_ctx, -1)) {
        std::string value(duk_get_string(m_ctx, -1));
        _val = StyleParam::parseString(_key, value);

    } else if (duk_is_boolean(m_ctx, -1)) {
        bool value = duk_get_boolean(m_ctx, -1);

        switch (_key) {
            case StyleParamKey::visible:
                _val = value;
                break;
            case StyleParamKey::extrude:
                _val = value ? glm::vec2(NAN, NAN) : glm::vec2(0.0f, 0.0f);
                break;
            default:
                break;
        }

    } else if (duk_is_array(m_ctx, -1)) {
        duk_get_prop_string(m_ctx, -1, "length");
        int len = duk_get_int(m_ctx, -1);
        duk_pop(m_ctx);

        switch (_key) {
            case StyleParamKey::extrude: {
                if (len != 2) {
                    LOGW("Wrong array size for extrusion: '%d'.", len);
                    break;
                }

                duk_get_prop_index(m_ctx, -1, 0);
                double v1 = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 1);
                double v2 = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                _val = glm::vec2(v1, v2);
                break;
            }
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::font_fill:
            case StyleParamKey::font_stroke_color: {
                if (len < 3 || len > 4) {
                    LOGW("Wrong array size for color: '%d'.", len);
                    break;
                }
                duk_get_prop_index(m_ctx, -1, 0);
                double r = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 1);
                double g = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 2);
                double b = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                double a = 1.0;
                if (len == 4) {
                    duk_get_prop_index(m_ctx, -1, 3);
                    a = duk_get_number(m_ctx, -1);
                    duk_pop(m_ctx);
                }

                _val = (((uint32_t)(255.0 * a) & 0xff) << 24) |
                       (((uint32_t)(255.0 * r) & 0xff)<< 16) |
                       (((uint32_t)(255.0 * g) & 0xff)<< 8) |
                       (((uint32_t)(255.0 * b) & 0xff));
                break;
            }
            default:
                break;
        }

    } else if (duk_is_number(m_ctx, -1)) {

        switch (_key) {
            case StyleParamKey::width:
            case StyleParamKey::outline_width:
            case StyleParamKey::font_stroke_width: {
                double v = duk_get_number(m_ctx, -1);
                _val = StyleParam::Width{static_cast<float>(v)};
                break;
            }
            case StyleParamKey::order:
            case StyleParamKey::priority:
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::font_fill:
            case StyleParamKey::font_stroke_color: {
                _val = static_cast<uint32_t>(duk_get_uint(m_ctx, -1));
                break;
            }
            default:
                break;
        }
    } else {
        LOGW("Unhandled return type from Javascript function.");
    }

    duk_pop(m_ctx);

    DUMP("parseStyleResult\n");
    return !_val.is<none_type>();
}

bool StyleContext::evalStyle(FunctionID _id, StyleParamKey _key, StyleParam::Value& _val) const {
    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
        LOGE("EvalFilterFn - functions array not initialized");
        return false;
    }

    if (!duk_get_prop_index(m_ctx, -1, _id)) {
        LOGE("EvalFilterFn - function %d not set", _id);
    }

    // pop fns array
    duk_remove(m_ctx, -2);

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
        duk_pop(m_ctx);
        return false;
    }

    return parseStyleResult(_key, _val);
}

bool StyleContext::evalStyleFn(const std::string& name, StyleParamKey _key, StyleParam::Value& _val) {
    if (!duk_get_global_string(m_ctx, name.c_str())) {
        LOGE("EvalFilter %s", name.c_str());
        return false;
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalStyleFn: %s", duk_safe_to_string(m_ctx, -1));
        duk_pop(m_ctx);
        return false;
    }

    return parseStyleResult(_key, _val);
}

void StyleContext::addAccessor(const std::string& _name) {

    auto it = m_accessors.find(_name);
    if (it != m_accessors.end()) {
        return;
    }

    auto entry = m_accessors.emplace(_name, Accessor{_name, this});
    if (!entry.second) {
        return; // hmm, already added..
    }

    Accessor& attr = (*entry.first).second;

    // push 'feature' obj onto stack
    if (!duk_get_global_string(m_ctx, "feature")) {
        LOGE("'feature' not in global scope");
        return;
    }

    // push property name
    duk_push_string(m_ctx, _name.c_str());

    // push getter function
    duk_push_c_function(m_ctx, jsPropertyGetter, 0 /*nargs*/);
    duk_push_pointer(m_ctx, (void*)&attr);
    duk_put_prop_string(m_ctx, -2, ATTR_ID);

    // push setter function
    // duk_push_c_function(m_ctx, jsPropertySetter, 1 /*nargs*/);
    // duk_push_pointer(m_ctx, (void*)&attr);
    // duk_put_prop_string(m_ctx, -2, ATTR_ID);

    // stack: [ feature_obj, name, getter, setter ] -> [ feature_obj.name ]
    duk_def_prop(m_ctx, -3,
                 DUK_DEFPROP_HAVE_GETTER |
                 // DUK_DEFPROP_HAVE_SETTER |
                 // DUK_DEFPROP_WRITABLE |
                 // DUK_DEFPROP_HAVE_ENUMERABLE |
                 // DUK_DEFPROP_ENUMERABLE |
                 // DUK_DEFPROP_HAVE_CONFIGURABLE |
                 0);

    // pop feature obj
    duk_pop(m_ctx);

    DUMP("addAccessor\n");
}

duk_ret_t StyleContext::jsPropertyGetter(duk_context *_ctx) {

    // Storing state for a Duktape/C function:
    // http://duktape.org/guide.html#programming.9
    duk_push_current_function(_ctx);
    duk_get_prop_string(_ctx, -1, ATTR_ID);
    auto* attr = static_cast<const Accessor*> (duk_to_pointer(_ctx, -1));

    if (!attr || !attr->ctx || !attr->ctx->m_feature) {
        LOGE("Error: no context set %p %p",
               attr,
               attr ? attr->ctx : nullptr);

        duk_pop(_ctx);
        return 0;
    }

    auto it = attr->ctx->m_feature->props.get(attr->key);

    if (it.is<std::string>()) {
        duk_push_string(_ctx, it.get<std::string>().c_str());
    } else if (it.is<float>()) {
        duk_push_number(_ctx, it.get<float>());
    } else {
        duk_push_undefined(_ctx);
    }

    return 1;
}

duk_ret_t StyleContext::jsPropertySetter(duk_context *_ctx) {
    return 0;
}

}
<commit_msg>fix: stroke width is still just a float<commit_after>#include "styleContext.h"
#include "platform.h"
#include "builders.h"
#include "scene/scene.h"

#define DUMP(...) //do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)

namespace Tangram {

const static char DATA_ID[] = "\xff""\xff""data";
const static char ATTR_ID[] = "\xff""\xff""attr";
const static char FUNC_ID[] = "\xff""\xff""fns";

StyleContext::StyleContext() {
    m_ctx = duk_create_heap_default();

    // add empty feature_object
    duk_push_object(m_ctx);

    // assign instance to feature_object
    duk_push_pointer(m_ctx, this);
    if (!duk_put_prop_string(m_ctx, -2, DATA_ID)) {
        LOGE("Ctx not assigned");
    }

    // put object in global scope
    if (!duk_put_global_string(m_ctx, "feature")) {
        LOGE("Feature not assigned");
    }

    DUMP("init\n");
}

StyleContext::~StyleContext() {
    duk_destroy_heap(m_ctx);
}

void StyleContext::initFunctions(const Scene& _scene) {

    if (_scene.id == m_sceneId) {
        return;
    }
    m_sceneId = _scene.id;

    auto arr_idx = duk_push_array(m_ctx);
    int id = 0;

    for (auto& function : _scene.functions()) {
        LOGD("compile '%s'", function.c_str());
        duk_push_string(m_ctx, function.c_str());
        duk_push_string(m_ctx, "");

        if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) == 0) {
            duk_put_prop_index(m_ctx, arr_idx, id);
        } else {
            LOGE("Compile failed: %s", duk_safe_to_string(m_ctx, -1));
            duk_pop(m_ctx);
        }
        id++;
    }

    if (!duk_put_global_string(m_ctx, FUNC_ID)) {
        LOGE("'fns' object not set");
    }

    DUMP("setScene - %d functions\n", id);
}

void StyleContext::setFeature(const Feature& _feature) {
    m_feature = &_feature;

    for (auto& item : _feature.props.items()) {
        addAccessor(item.key);
    }
}

void StyleContext::setGlobalZoom(float _zoom) {
    static const std::string _key("$zoom");
    if (_zoom != m_globalZoom) {
        setGlobal(_key, _zoom);
    }
}

void StyleContext::setGlobal(const std::string& _key, const Value& _val) {
    Value& entry = m_globals[_key];
    if (entry == _val) { return; }

    entry = _val;

    if (_val.is<float>()) {
        duk_push_number(m_ctx, _val.get<float>());
        duk_put_global_string(m_ctx, _key.c_str());

        if (_key == "$zoom") { m_globalZoom = _val.get<float>(); }

    } else if (_val.is<std::string>()) {
        duk_push_string(m_ctx, _val.get<std::string>().c_str());
        duk_put_global_string(m_ctx, _key.c_str());
    }
}

const Value& StyleContext::getGlobal(const std::string& _key) const {

    const static Value NOT_FOUND(none_type{});

    auto it = m_globals.find(_key);
    if (it != m_globals.end()) {
        return it->second;
    }
    return NOT_FOUND;
}

void StyleContext::clear() {
    m_feature = nullptr;
}

bool StyleContext::addFunction(const std::string& _name, const std::string& _func) {

    duk_push_string(m_ctx, _func.c_str());
    duk_push_string(m_ctx, _name.c_str());

    if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) != 0) {
        LOGE("Compile failed: %s", duk_safe_to_string(m_ctx, -1));
        return false;
    }

    // Put function in global scope
    duk_put_global_string(m_ctx, _name.c_str());

    DUMP("addFunction\n");
    return true;
}

bool StyleContext::evalFilter(FunctionID _id) const {
    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
        LOGE("EvalFilterFn - functions not initialized");
        return false;
    }

    if (!duk_get_prop_index(m_ctx, -1, _id)) {
        LOGE("EvalFilterFn - function %d not set", _id);
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
    }

    bool result = false;

    if (duk_is_boolean(m_ctx, -1)) {
        result = duk_get_boolean(m_ctx, -1);
    }

    // pop result
    duk_pop(m_ctx);
    // pop fns obj
    duk_pop(m_ctx);

    DUMP("evalFilterFn\n");
    return result;
}

bool StyleContext::evalFilterFn(const std::string& _name) {
    if (!duk_get_global_string(m_ctx, _name.c_str())) {
        LOGE("EvalFilter %s", _name.c_str());
        return false;
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
    }

    bool result = false;

    if (duk_is_boolean(m_ctx, -1)) {
        result = duk_get_boolean(m_ctx, -1);
    }

    // pop result
    duk_pop(m_ctx);

    DUMP("evalFilterFn\n");
    return result;
}

bool StyleContext::parseStyleResult(StyleParamKey _key, StyleParam::Value& _val) const {
    _val = none_type{};

    if (duk_is_string(m_ctx, -1)) {
        std::string value(duk_get_string(m_ctx, -1));
        _val = StyleParam::parseString(_key, value);

    } else if (duk_is_boolean(m_ctx, -1)) {
        bool value = duk_get_boolean(m_ctx, -1);

        switch (_key) {
            case StyleParamKey::visible:
                _val = value;
                break;
            case StyleParamKey::extrude:
                _val = value ? glm::vec2(NAN, NAN) : glm::vec2(0.0f, 0.0f);
                break;
            default:
                break;
        }

    } else if (duk_is_array(m_ctx, -1)) {
        duk_get_prop_string(m_ctx, -1, "length");
        int len = duk_get_int(m_ctx, -1);
        duk_pop(m_ctx);

        switch (_key) {
            case StyleParamKey::extrude: {
                if (len != 2) {
                    LOGW("Wrong array size for extrusion: '%d'.", len);
                    break;
                }

                duk_get_prop_index(m_ctx, -1, 0);
                double v1 = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 1);
                double v2 = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                _val = glm::vec2(v1, v2);
                break;
            }
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::font_fill:
            case StyleParamKey::font_stroke_color: {
                if (len < 3 || len > 4) {
                    LOGW("Wrong array size for color: '%d'.", len);
                    break;
                }
                duk_get_prop_index(m_ctx, -1, 0);
                double r = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 1);
                double g = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                duk_get_prop_index(m_ctx, -1, 2);
                double b = duk_get_number(m_ctx, -1);
                duk_pop(m_ctx);

                double a = 1.0;
                if (len == 4) {
                    duk_get_prop_index(m_ctx, -1, 3);
                    a = duk_get_number(m_ctx, -1);
                    duk_pop(m_ctx);
                }

                _val = (((uint32_t)(255.0 * a) & 0xff) << 24) |
                       (((uint32_t)(255.0 * r) & 0xff)<< 16) |
                       (((uint32_t)(255.0 * g) & 0xff)<< 8) |
                       (((uint32_t)(255.0 * b) & 0xff));
                break;
            }
            default:
                break;
        }

    } else if (duk_is_number(m_ctx, -1)) {

        switch (_key) {
            case StyleParamKey::width:
            case StyleParamKey::outline_width: {
                // TODO more efficient way to return pixels.
                // atm this only works by return value as string
                double v = duk_get_number(m_ctx, -1);
                _val = StyleParam::Width{static_cast<float>(v)};
                break;
            }
            case StyleParamKey::font_stroke_width: {
                double v = duk_get_number(m_ctx, -1);
                _val = static_cast<float>(v);
                break;
            }
            case StyleParamKey::order:
            case StyleParamKey::priority:
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::font_fill:
            case StyleParamKey::font_stroke_color: {
                _val = static_cast<uint32_t>(duk_get_uint(m_ctx, -1));
                break;
            }
            default:
                break;
        }
    } else {
        LOGW("Unhandled return type from Javascript function.");
    }

    duk_pop(m_ctx);

    DUMP("parseStyleResult\n");
    return !_val.is<none_type>();
}

bool StyleContext::evalStyle(FunctionID _id, StyleParamKey _key, StyleParam::Value& _val) const {
    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
        LOGE("EvalFilterFn - functions array not initialized");
        return false;
    }

    if (!duk_get_prop_index(m_ctx, -1, _id)) {
        LOGE("EvalFilterFn - function %d not set", _id);
    }

    // pop fns array
    duk_remove(m_ctx, -2);

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
        duk_pop(m_ctx);
        return false;
    }

    return parseStyleResult(_key, _val);
}

bool StyleContext::evalStyleFn(const std::string& name, StyleParamKey _key, StyleParam::Value& _val) {
    if (!duk_get_global_string(m_ctx, name.c_str())) {
        LOGE("EvalFilter %s", name.c_str());
        return false;
    }

    if (duk_pcall(m_ctx, 0) != 0) {
        LOGE("EvalStyleFn: %s", duk_safe_to_string(m_ctx, -1));
        duk_pop(m_ctx);
        return false;
    }

    return parseStyleResult(_key, _val);
}

void StyleContext::addAccessor(const std::string& _name) {

    auto it = m_accessors.find(_name);
    if (it != m_accessors.end()) {
        return;
    }

    auto entry = m_accessors.emplace(_name, Accessor{_name, this});
    if (!entry.second) {
        return; // hmm, already added..
    }

    Accessor& attr = (*entry.first).second;

    // push 'feature' obj onto stack
    if (!duk_get_global_string(m_ctx, "feature")) {
        LOGE("'feature' not in global scope");
        return;
    }

    // push property name
    duk_push_string(m_ctx, _name.c_str());

    // push getter function
    duk_push_c_function(m_ctx, jsPropertyGetter, 0 /*nargs*/);
    duk_push_pointer(m_ctx, (void*)&attr);
    duk_put_prop_string(m_ctx, -2, ATTR_ID);

    // push setter function
    // duk_push_c_function(m_ctx, jsPropertySetter, 1 /*nargs*/);
    // duk_push_pointer(m_ctx, (void*)&attr);
    // duk_put_prop_string(m_ctx, -2, ATTR_ID);

    // stack: [ feature_obj, name, getter, setter ] -> [ feature_obj.name ]
    duk_def_prop(m_ctx, -3,
                 DUK_DEFPROP_HAVE_GETTER |
                 // DUK_DEFPROP_HAVE_SETTER |
                 // DUK_DEFPROP_WRITABLE |
                 // DUK_DEFPROP_HAVE_ENUMERABLE |
                 // DUK_DEFPROP_ENUMERABLE |
                 // DUK_DEFPROP_HAVE_CONFIGURABLE |
                 0);

    // pop feature obj
    duk_pop(m_ctx);

    DUMP("addAccessor\n");
}

duk_ret_t StyleContext::jsPropertyGetter(duk_context *_ctx) {

    // Storing state for a Duktape/C function:
    // http://duktape.org/guide.html#programming.9
    duk_push_current_function(_ctx);
    duk_get_prop_string(_ctx, -1, ATTR_ID);
    auto* attr = static_cast<const Accessor*> (duk_to_pointer(_ctx, -1));

    if (!attr || !attr->ctx || !attr->ctx->m_feature) {
        LOGE("Error: no context set %p %p",
               attr,
               attr ? attr->ctx : nullptr);

        duk_pop(_ctx);
        return 0;
    }

    auto it = attr->ctx->m_feature->props.get(attr->key);

    if (it.is<std::string>()) {
        duk_push_string(_ctx, it.get<std::string>().c_str());
    } else if (it.is<float>()) {
        duk_push_number(_ctx, it.get<float>());
    } else {
        duk_push_undefined(_ctx);
    }

    return 1;
}

duk_ret_t StyleContext::jsPropertySetter(duk_context *_ctx) {
    return 0;
}

}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// This file implements logic for lowering MHLO general dot to a regular dot.

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/Pass/Pass.h"

using mlir::DenseIntElementsAttr;
using mlir::ElementsAttr;
using mlir::failure;
using mlir::FunctionPass;
using mlir::LogicalResult;
using mlir::MLIRContext;
using mlir::OpRewritePattern;
using mlir::OwningRewritePatternList;
using mlir::PassRegistration;
using mlir::PassWrapper;
using mlir::PatternRewriter;
using mlir::RankedTensorType;
using mlir::success;
using mlir::Value;

namespace {

Value TransposeReshape(Value arg, mlir::Location loc,
                       llvm::ArrayRef<int64_t> left_dims,
                       llvm::ArrayRef<int64_t> right_dims,
                       llvm::ArrayRef<int64_t> arg_shape,
                       PatternRewriter *rewriter) {
  auto element_type = mlir::getElementTypeOrSelf(arg.getType());

  int64_t left_size = 1;
  for (auto dim : left_dims) {
    left_size *= arg_shape[dim];
  }

  int64_t right_size = 1;
  for (auto dim : right_dims) {
    right_size *= arg_shape[dim];
  }

  // Generate the transpose permutation attribute.
  llvm::SmallVector<int64_t, 5> transpose_permutation(left_dims.begin(),
                                                      left_dims.end());
  transpose_permutation.append(right_dims.begin(), right_dims.end());

  mlir::TensorType transpose_permutation_type = RankedTensorType::get(
      {static_cast<int64_t>(transpose_permutation.size())},
      rewriter->getIntegerType(64));

  auto transpose_permutation_attr =
      DenseIntElementsAttr::get(transpose_permutation_type,
                                llvm::makeArrayRef(transpose_permutation))
          .cast<DenseIntElementsAttr>();

  // Compute the resulting shape.
  llvm::SmallVector<int64_t, 5> transposed_shape;
  for (auto val : transpose_permutation) {
    transposed_shape.push_back(arg_shape[val]);
  }
  auto transpose_type = RankedTensorType::get(transposed_shape, element_type);
  auto transpose_result = rewriter->create<mlir::mhlo::TransposeOp>(
      loc, transpose_type, arg, transpose_permutation_attr);

  // Return the final result.
  auto reshaped_type =
      RankedTensorType::get({left_size, right_size}, element_type);
  return rewriter->create<mlir::mhlo::ReshapeOp>(loc, reshaped_type,
                                                 transpose_result);
}

Value ProcessDotArg(Value arg, mlir::Location loc,
                    ElementsAttr contract_dims_attr, bool outer_dims_first,
                    PatternRewriter *rewriter) {
  auto shape = arg.getType().cast<mlir::ShapedType>().getShape();

  llvm::SmallVector<bool, 5> is_outer_dim;
  is_outer_dim.resize(shape.size(), true);

  // Compute the contract dimension ordering.
  llvm::SmallVector<int64_t, 5> contract_dims;
  for (auto dim : contract_dims_attr.getValues<int64_t>()) {
    contract_dims.push_back(dim);
    is_outer_dim[dim] = false;
  }

  // Compute the outer dimension orderings.
  llvm::SmallVector<int64_t, 5> outer_dims;
  for (auto it : llvm::enumerate(is_outer_dim)) {
    if (it.value()) {
      outer_dims.push_back(it.index());
    }
  }

  if (outer_dims_first) {
    return TransposeReshape(arg, loc, outer_dims, contract_dims, shape,
                            rewriter);
  }

  return TransposeReshape(arg, loc, contract_dims, outer_dims, shape, rewriter);
}

struct GeneralDotConvert : public OpRewritePattern<mlir::mhlo::DotGeneralOp> {
  // Attempts to lower a General Dot operator to a standard Dot operator.
  // General dots include batching dimensions and can have collapsing
  // dimensions along any axis. Inserting correctly arrange transpose and
  // reshape operators organizes the tensors and allows the General Dot to be
  // replaced with the standard Dot operator.
  //
  // Note: This requires an empty list of batch dimensions.

  explicit GeneralDotConvert(MLIRContext *context)
      : OpRewritePattern(context) {}

  LogicalResult matchAndRewrite(mlir::mhlo::DotGeneralOp op,
                                PatternRewriter &rewriter) const override {
    auto dot_element_type = mlir::getElementTypeOrSelf(op);

    auto dot_numbers = op.dot_dimension_numbers();
    if (dot_numbers.lhs_batching_dimensions().getNumElements() != 0 ||
        dot_numbers.rhs_batching_dimensions().getNumElements() != 0) {
      return failure();
    }

    auto lhs = ProcessDotArg(op.lhs(), op.getLoc(),
                             dot_numbers.lhs_contracting_dimensions(),
                             /*outer_dims_first=*/true, &rewriter);

    auto rhs = ProcessDotArg(op.rhs(), op.getLoc(),
                             dot_numbers.rhs_contracting_dimensions(),
                             /*outer_dims_first=*/false, &rewriter);

    // Dot resulting shape.
    auto lhs_shape = lhs.getType().cast<mlir::ShapedType>().getShape();
    auto rhs_shape = rhs.getType().cast<mlir::ShapedType>().getShape();
    auto new_dot_type =
        RankedTensorType::get({lhs_shape[0], rhs_shape[1]}, dot_element_type);

    auto new_dot_op = rewriter.create<mlir::mhlo::DotOp>(
        op.getLoc(), new_dot_type, lhs, rhs, *(op.precision_config()));

    rewriter.replaceOpWithNewOp<mlir::mhlo::ReshapeOp>(op, op.getType(),
                                                       new_dot_op);
    return success();
  }
};

struct LegalizeGeneralDotPass
    : public PassWrapper<LegalizeGeneralDotPass, FunctionPass> {
  /// Lower all general dots that can be represented as a non-batched matmul.
  void runOnFunction() override {
    OwningRewritePatternList patterns;
    mlir::mhlo::PopulateGeneralDotOpLoweringPatterns(&patterns, &getContext());
    applyPatternsAndFoldGreedily(getFunction(), patterns);
  }
};

}  // namespace

void mlir::mhlo::PopulateGeneralDotOpLoweringPatterns(
    OwningRewritePatternList *patterns, MLIRContext *ctx) {
  patterns->insert<GeneralDotConvert>(ctx);
}

std::unique_ptr<::mlir::Pass> mlir::mhlo::createLegalizeGeneralDotPass() {
  return std::make_unique<LegalizeGeneralDotPass>();
}
<commit_msg>Only apply GeneralDotOpLoweringPatterns for static shaped inputs<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// This file implements logic for lowering MHLO general dot to a regular dot.

#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "mlir-hlo/Dialect/mhlo/IR/hlo_ops.h"
#include "mlir-hlo/Dialect/mhlo/transforms/passes.h"
#include "mlir-hlo/Dialect/mhlo/transforms/rewriters.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/Pass/Pass.h"

using mlir::DenseIntElementsAttr;
using mlir::ElementsAttr;
using mlir::failure;
using mlir::FunctionPass;
using mlir::LogicalResult;
using mlir::MLIRContext;
using mlir::OpRewritePattern;
using mlir::OwningRewritePatternList;
using mlir::PassRegistration;
using mlir::PassWrapper;
using mlir::PatternRewriter;
using mlir::RankedTensorType;
using mlir::success;
using mlir::Value;

namespace {

Value TransposeReshape(Value arg, mlir::Location loc,
                       llvm::ArrayRef<int64_t> left_dims,
                       llvm::ArrayRef<int64_t> right_dims,
                       llvm::ArrayRef<int64_t> arg_shape,
                       PatternRewriter *rewriter) {
  auto element_type = mlir::getElementTypeOrSelf(arg.getType());

  int64_t left_size = 1;
  for (auto dim : left_dims) {
    left_size *= arg_shape[dim];
  }

  int64_t right_size = 1;
  for (auto dim : right_dims) {
    right_size *= arg_shape[dim];
  }

  // Generate the transpose permutation attribute.
  llvm::SmallVector<int64_t, 5> transpose_permutation(left_dims.begin(),
                                                      left_dims.end());
  transpose_permutation.append(right_dims.begin(), right_dims.end());

  mlir::TensorType transpose_permutation_type = RankedTensorType::get(
      {static_cast<int64_t>(transpose_permutation.size())},
      rewriter->getIntegerType(64));

  auto transpose_permutation_attr =
      DenseIntElementsAttr::get(transpose_permutation_type,
                                llvm::makeArrayRef(transpose_permutation))
          .cast<DenseIntElementsAttr>();

  // Compute the resulting shape.
  llvm::SmallVector<int64_t, 5> transposed_shape;
  for (auto val : transpose_permutation) {
    transposed_shape.push_back(arg_shape[val]);
  }
  auto transpose_type = RankedTensorType::get(transposed_shape, element_type);
  auto transpose_result = rewriter->create<mlir::mhlo::TransposeOp>(
      loc, transpose_type, arg, transpose_permutation_attr);

  // Return the final result.
  auto reshaped_type =
      RankedTensorType::get({left_size, right_size}, element_type);
  return rewriter->create<mlir::mhlo::ReshapeOp>(loc, reshaped_type,
                                                 transpose_result);
}

Value ProcessDotArg(Value arg, mlir::Location loc,
                    ElementsAttr contract_dims_attr, bool outer_dims_first,
                    PatternRewriter *rewriter) {
  auto shape = arg.getType().cast<mlir::ShapedType>().getShape();

  llvm::SmallVector<bool, 5> is_outer_dim;
  is_outer_dim.resize(shape.size(), true);

  // Compute the contract dimension ordering.
  llvm::SmallVector<int64_t, 5> contract_dims;
  for (auto dim : contract_dims_attr.getValues<int64_t>()) {
    contract_dims.push_back(dim);
    is_outer_dim[dim] = false;
  }

  // Compute the outer dimension orderings.
  llvm::SmallVector<int64_t, 5> outer_dims;
  for (auto it : llvm::enumerate(is_outer_dim)) {
    if (it.value()) {
      outer_dims.push_back(it.index());
    }
  }

  if (outer_dims_first) {
    return TransposeReshape(arg, loc, outer_dims, contract_dims, shape,
                            rewriter);
  }

  return TransposeReshape(arg, loc, contract_dims, outer_dims, shape, rewriter);
}

struct GeneralDotConvert : public OpRewritePattern<mlir::mhlo::DotGeneralOp> {
  // Attempts to lower a General Dot operator to a standard Dot operator.
  // General dots include batching dimensions and can have collapsing
  // dimensions along any axis. Inserting correctly arrange transpose and
  // reshape operators organizes the tensors and allows the General Dot to be
  // replaced with the standard Dot operator.
  //
  // Note: This requires an empty list of batch dimensions.

  explicit GeneralDotConvert(MLIRContext *context)
      : OpRewritePattern(context) {}

  LogicalResult matchAndRewrite(mlir::mhlo::DotGeneralOp op,
                                PatternRewriter &rewriter) const override {
    auto dot_element_type = mlir::getElementTypeOrSelf(op);

    auto dot_numbers = op.dot_dimension_numbers();
    if (dot_numbers.lhs_batching_dimensions().getNumElements() != 0 ||
        dot_numbers.rhs_batching_dimensions().getNumElements() != 0) {
      return failure();
    }

    auto lhs = ProcessDotArg(op.lhs(), op.getLoc(),
                             dot_numbers.lhs_contracting_dimensions(),
                             /*outer_dims_first=*/true, &rewriter);

    auto rhs = ProcessDotArg(op.rhs(), op.getLoc(),
                             dot_numbers.rhs_contracting_dimensions(),
                             /*outer_dims_first=*/false, &rewriter);

    // Accept only static shaped types.
    auto lhs_shape_type = lhs.getType().dyn_cast_or_null<mlir::ShapedType>();
    auto rhs_shape_type = rhs.getType().dyn_cast_or_null<mlir::ShapedType>();
    if (!lhs_shape_type || !rhs_shape_type) return failure();
    if (!lhs_shape_type.hasStaticShape() || !rhs_shape_type.hasStaticShape())
      return failure();

    // Dot resulting shape.
    auto lhs_shape = lhs_shape_type.getShape();
    auto rhs_shape = rhs_shape_type.getShape();
    auto new_dot_type =
        RankedTensorType::get({lhs_shape[0], rhs_shape[1]}, dot_element_type);

    auto new_dot_op = rewriter.create<mlir::mhlo::DotOp>(
        op.getLoc(), new_dot_type, lhs, rhs, *(op.precision_config()));

    rewriter.replaceOpWithNewOp<mlir::mhlo::ReshapeOp>(op, op.getType(),
                                                       new_dot_op);
    return success();
  }
};

struct LegalizeGeneralDotPass
    : public PassWrapper<LegalizeGeneralDotPass, FunctionPass> {
  /// Lower all general dots that can be represented as a non-batched matmul.
  void runOnFunction() override {
    OwningRewritePatternList patterns;
    mlir::mhlo::PopulateGeneralDotOpLoweringPatterns(&patterns, &getContext());
    applyPatternsAndFoldGreedily(getFunction(), patterns);
  }
};

}  // namespace

void mlir::mhlo::PopulateGeneralDotOpLoweringPatterns(
    OwningRewritePatternList *patterns, MLIRContext *ctx) {
  patterns->insert<GeneralDotConvert>(ctx);
}

std::unique_ptr<::mlir::Pass> mlir::mhlo::createLegalizeGeneralDotPass() {
  return std::make_unique<LegalizeGeneralDotPass>();
}
<|endoftext|>


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

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }
};

// Disabled: see http://crbug.com/101170
IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DISABLED_Downloads) {
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<commit_msg>DownloadsApiTest uses a ScopedTempDir to clean up after itself. BUG=101162<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }

  void SetUpTempDownloadsDir() {
    ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, tmpdir.path());
  }

 private:
  ScopedTempDir tmpdir;
};

IN_PROC_BROWSER_TEST_F(DownloadsApiTest, Downloads) {
  SetUpTempDownloadsDir();
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
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 author 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.

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iomanip>
#include <boost/bind.hpp>

#include "libtorrent/kademlia/node_id.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp"

using boost::bind;

namespace libtorrent { namespace dht
{

// returns the distance between the two nodes
// using the kademlia XOR-metric
node_id distance(node_id const& n1, node_id const& n2)
{
	node_id ret;
	node_id::iterator k = ret.begin();
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, end(n1.end()); i != end; ++i, ++j, ++k)
	{
		*k = *i ^ *j;
	}
	return ret;
}

// returns true if: distance(n1, ref) < distance(n2, ref)
bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
{
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, k = ref.begin(), end(n1.end()); i != end; ++i, ++j, ++k)
	{
		boost::uint8_t lhs = (*i ^ *k);
		boost::uint8_t rhs = (*j ^ *k);
		if (lhs < rhs) return true;
		if (lhs > rhs) return false;
	}
	return false;
}

// returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
// useful for finding out which bucket a node belongs to
int distance_exp(node_id const& n1, node_id const& n2)
{
	int byte = node_id::size - 1;
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, end(n1.end()); i != end; ++i, ++j, --byte)
	{
		TORRENT_ASSERT(byte >= 0);
		boost::uint8_t t = *i ^ *j;
		if (t == 0) continue;
		// we have found the first non-zero byte
		// return the bit-number of the first bit
		// that differs
		int bit = byte * 8;
		for (int b = 7; b >= 0; --b)
			if (t >= (1 << b)) return bit + b;
		return bit;
	}

	return 0;
}

struct static_ { static_() { std::srand(std::time(0)); } } static__;

node_id generate_id()
{
	char random[20];
#ifdef _MSC_VER
	std::generate(random, random + 20, &rand);
#else
	std::generate(random, random + 20, &std::rand);
#endif

	hasher h;
	h.update(random, 20);
	return h.final();
}

} }  // namespace libtorrent::dht

<commit_msg>added missing include statement<commit_after>/*

Copyright (c) 2006, Arvid Norberg
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 author 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.

*/

#include "libtorrent/pch.hpp"

#include <algorithm>
#include <iomanip>
#include <ctime>
#include <boost/bind.hpp>

#include "libtorrent/kademlia/node_id.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp"

using boost::bind;

namespace libtorrent { namespace dht
{

// returns the distance between the two nodes
// using the kademlia XOR-metric
node_id distance(node_id const& n1, node_id const& n2)
{
	node_id ret;
	node_id::iterator k = ret.begin();
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, end(n1.end()); i != end; ++i, ++j, ++k)
	{
		*k = *i ^ *j;
	}
	return ret;
}

// returns true if: distance(n1, ref) < distance(n2, ref)
bool compare_ref(node_id const& n1, node_id const& n2, node_id const& ref)
{
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, k = ref.begin(), end(n1.end()); i != end; ++i, ++j, ++k)
	{
		boost::uint8_t lhs = (*i ^ *k);
		boost::uint8_t rhs = (*j ^ *k);
		if (lhs < rhs) return true;
		if (lhs > rhs) return false;
	}
	return false;
}

// returns n in: 2^n <= distance(n1, n2) < 2^(n+1)
// useful for finding out which bucket a node belongs to
int distance_exp(node_id const& n1, node_id const& n2)
{
	int byte = node_id::size - 1;
	for (node_id::const_iterator i = n1.begin(), j = n2.begin()
		, end(n1.end()); i != end; ++i, ++j, --byte)
	{
		TORRENT_ASSERT(byte >= 0);
		boost::uint8_t t = *i ^ *j;
		if (t == 0) continue;
		// we have found the first non-zero byte
		// return the bit-number of the first bit
		// that differs
		int bit = byte * 8;
		for (int b = 7; b >= 0; --b)
			if (t >= (1 << b)) return bit + b;
		return bit;
	}

	return 0;
}

struct static_ { static_() { std::srand(std::time(0)); } } static__;

node_id generate_id()
{
	char random[20];
#ifdef _MSC_VER
	std::generate(random, random + 20, &rand);
#else
	std::generate(random, random + 20, &std::rand);
#endif

	hasher h;
	h.update(random, 20);
	return h.final();
}

} }  // namespace libtorrent::dht

<|endoftext|>


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

#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-enabled split-mode extension work
// properly.
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
// Hanging on ChromeOS and linux: http://crbug.com/53991
#define MAYBE_IncognitoSplitMode DISABLED_IncognitoSplitMode
#else
#define MAYBE_IncognitoSplitMode IncognitoSplitMode
#endif
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_IncognitoSplitMode) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // We need 2 ResultCatchers because we'll be running the same test in both
  // regular and incognito mode.
  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("split")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
// Hangy, http://crbug.com/53869.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<commit_msg>Disable IncognitoSplitMode everywhere, it's failing and hangy. Working on a fix.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoNoScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script didn't run.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'Unmodified')",
      &result);
  EXPECT_TRUE(result);
}

IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, IncognitoYesScript) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // Load a dummy extension. This just tests that we don't regress a
  // crash fix when multiple incognito- and non-incognito-enabled extensions
  // are mixed.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("all_frames")));

  // Loads a simple extension which attempts to change the title of every page
  // that loads to "modified".
  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("incognito").AppendASCII("content_scripts")));

  // Dummy extension #2.
  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
      .AppendASCII("content_scripts").AppendASCII("isolated_world1")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* otr_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);
  TabContents* tab = otr_browser->GetSelectedTabContents();

  // Verify the script ran.
  bool result = false;
  ui_test_utils::ExecuteJavaScriptAndExtractBool(
      tab->render_view_host(), L"",
      L"window.domAutomationController.send(document.title == 'modified')",
      &result);
  EXPECT_TRUE(result);
}

// Tests that the APIs in an incognito-enabled extension work properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Incognito) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-enabled split-mode extension work
// properly.
// Hanging/failing: http://crbug.com/53991
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoSplitMode) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  // We need 2 ResultCatchers because we'll be running the same test in both
  // regular and incognito mode.
  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());
  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("split")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_TRUE(catcher_incognito.GetNextResult()) << catcher.message();
}

// Tests that the APIs in an incognito-disabled extension don't see incognito
// events or callbacks.
// Hangy, http://crbug.com/53869.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_IncognitoDisabled) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));

  ASSERT_TRUE(LoadExtension(test_data_dir_
      .AppendASCII("incognito").AppendASCII("apis_disabled")));

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}

// Test that opening a popup from an incognito browser window works properly.
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, IncognitoPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  ResultCatcher catcher;

  ASSERT_TRUE(LoadExtensionIncognito(test_data_dir_
      .AppendASCII("incognito").AppendASCII("popup")));

  // Open incognito window and navigate to test page.
  ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
      GURL("http://www.example.com:1337/files/extensions/test_file.html"));
  Browser* incognito_browser = BrowserList::FindBrowserWithType(
      browser()->profile()->GetOffTheRecordProfile(), Browser::TYPE_NORMAL,
      false);

  // Simulate the incognito's browser action being clicked.
  BrowserActionTestUtil(incognito_browser).Press(0);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
<|endoftext|>