<commit_before>//
//  CompositeTileImageProvider.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/23/14.
//
//

#include "CompositeTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "Tile.hpp"
#include "CompositeTileImageContribution.hpp"
#include "IFactory.hpp"
#include "ICanvas.hpp"
#include "IImage.hpp"
#include "FrameTasksExecutor.hpp"

CompositeTileImageProvider::~CompositeTileImageProvider() {
  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    child->_release();
  }
#ifdef JAVA_CODE
  super.dispose();
#endif
}

const TileImageContribution* CompositeTileImageProvider::contribution(const Tile* tile) {
  std::vector<const CompositeTileImageContribution::ChildContribution*> childrenContributions;

  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    const TileImageContribution* childContribution = child->contribution(tile);
    if (childContribution != NULL) {
      // ignore previous contributions, they are covered by the current fullCoverage & Opaque contribution.
      const int childrenContributionsSize = childrenContributions.size();
      if ((childrenContributionsSize > 0) &&
          childContribution->isFullCoverageAndOpaque()) {
        for (int j = 0; j < childrenContributionsSize; j++) {
          const CompositeTileImageContribution::ChildContribution* previousContribution = childrenContributions[j];
#ifdef C_CODE
          delete previousContribution;
#endif
#ifdef JAVA_CODE
          previousContribution.dispose();
#endif
        }
        childrenContributions.clear();
      }

      childrenContributions.push_back( new CompositeTileImageContribution::ChildContribution(i, childContribution) );
    }
  }

  return CompositeTileImageContribution::create(childrenContributions);
}

CompositeTileImageProvider::ChildResult::ChildResult(const bool                   isError,
                                                     const bool                   isCanceled,
                                                     const IImage*                image,
                                                     const std::string&           imageId,
                                                     const TileImageContribution* contribution,
                                                     const std::string&           error) :
_isError(isError),
_isCanceled(isCanceled),
_image(image),
_imageId(imageId),
_contribution(contribution),
_error(error)
{
  //  TileImageContribution::retainContribution(_contribution);
}

CompositeTileImageProvider::ChildResult::~ChildResult() {
  delete _image;
  //  TileImageContribution::releaseContribution(_contribution);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::image(const IImage*                image,
                                                                                const std::string&           imageId,
                                                                                const TileImageContribution* contribution) {
  return new CompositeTileImageProvider::ChildResult(false ,       // isError
                                                     false,        // isCanceled
                                                     image,
                                                     imageId,
                                                     contribution,
                                                     ""            // error
                                                     );
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::error(const std::string& error) {
  return new CompositeTileImageProvider::ChildResult(true,  // isError
                                                     false, // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     error);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::cancelation() {
  return new CompositeTileImageProvider::ChildResult(false, // isError
                                                     true,  // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     ""     // error
                                                     );
}

CompositeTileImageProvider::Composer::Composer(int width,
                                               int height,
                                               CompositeTileImageProvider* compositeTileImageProvider,
                                               const std::string& tileId,
                                               const Sector& tileSector,
                                               TileImageListener* listener,
                                               bool deleteListener,
                                               const CompositeTileImageContribution* compositeContribution,
                                               FrameTasksExecutor* frameTasksExecutor) :
_width(width),
_height(height),
_compositeTileImageProvider(compositeTileImageProvider),
_tileId(tileId),
_listener(listener),
_deleteListener(deleteListener),
_compositeContribution(compositeContribution),
_contributionsSize( compositeContribution->size() ),
_frameTasksExecutor(frameTasksExecutor),
_stepsDone(0),
_anyError(false),
_anyCancelation(false),
_canceled(false),
_tileSector(tileSector)
{
#warning DEBUG MEMORY
  //  TileImageContribution::retainContribution(_compositeContribution);
  for (int i = 0; i < _contributionsSize; i++) {
    _results.push_back( NULL );
  }
}

CompositeTileImageProvider::Composer::~Composer() {
  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    delete result;
  }

  TileImageContribution::releaseContribution(_compositeContribution);

#ifdef JAVA_CODE
  super.dispose();
#endif
}

void CompositeTileImageProvider::Composer::cleanUp() {
  if (_deleteListener) {
    delete _listener;
    _listener = NULL;
  }

  _compositeTileImageProvider->composerDone(this);
}

void CompositeTileImageProvider::Composer::done() {
  if (_canceled) {
    cleanUp();
    return;
  }

  if (_contributionsSize == 1) {
    const ChildResult* singleResult = _results[0];

    if (singleResult->_isError) {
      _listener->imageCreationError(_tileId,
                                    singleResult->_error);
    }
    else if (singleResult->_isCanceled) {
      _listener->imageCreationCanceled(_tileId);
    }
    else {
      _listener->imageCreated(singleResult->_imageId,
                              singleResult->_image->shallowCopy(),
                              singleResult->_imageId,
                              singleResult->_contribution);
    }

    cleanUp();
  }
  else {
    if (_anyError) {
      std::string composedError = "";
      for (int i = 0; i < _contributionsSize; i++) {
        const ChildResult* childResult = _results[i];
        if (childResult->_isError) {
          composedError += childResult->_error + " ";
        }
      }

      _listener->imageCreationError(_tileId,
                                    composedError);

      cleanUp();
    }
    else if (_anyCancelation) {
      _listener->imageCreationCanceled(_tileId);
      cleanUp();
    }
    else {
      //      ICanvas* canvas = IFactory::instance()->createCanvas();
      //
      //      canvas->initialize(_width, _height);
      //
      //      std::string imageId = "";
      //
      //      for (int i = 0; i < _contributionsSize; i++) {
      //       const ChildResult* result = _results[i];
      //
      //        imageId += result->_imageId + "|";
      //#warning JM: consider sector and transparency
      //        canvas->drawImage(result->_image, 0, 0);
      //      }
      //      _imageId = imageId;
      //
      //      canvas->createImage(new ComposerImageListener(this), true);
      //
      //      delete canvas;

      _frameTasksExecutor->addPreRenderTask(new ComposerFrameTask(this));
    }
  }
}

RectangleF* CompositeTileImageProvider::Composer::getInnerRectangle(int wholeSectorWidth,
                                                                    int wholeSectorHeight,
                                                                    const Sector& wholeSector,
                                                                    const Sector& innerSector) const {
  if (wholeSector.isEquals(innerSector)){
    return new RectangleF(0, 0, wholeSectorWidth, wholeSectorHeight);
  }

  const double widthFactor  = innerSector._deltaLongitude.div(wholeSector._deltaLongitude);
  const double heightFactor = innerSector._deltaLatitude.div(wholeSector._deltaLatitude);

  const Vector2D lowerUV = wholeSector.getUVCoordinates(innerSector.getNW());

  return new RectangleF((float) (lowerUV._x   * wholeSectorWidth),
                        (float) (lowerUV._y   * wholeSectorHeight),
                        (float) (widthFactor  * wholeSectorWidth),
                        (float) (heightFactor * wholeSectorHeight));
}

void CompositeTileImageProvider::Composer::mixResult() {
  if (_canceled) {
    cleanUp();
    return;
  }

  ICanvas* canvas = IFactory::instance()->createCanvas();

  canvas->initialize(_width, _height);

  std::string imageId = "";

  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    imageId += result->_imageId + "|";

#warning //For now, we consider the whole image will appear on the tile (no source rect needed)
    const IImage* image = result->_image;
    const float   alpha = result->_contribution->_alpha;

    if (result->_contribution->isFullCoverageAndOpaque()) {
      canvas->drawImage(image, 0, 0);
    }
    else {
      if (result->_contribution->isFullCoverage()) {
        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          0, 0,
                          _width, _height,
                          alpha);
      }
      else {
        const Sector* imageSector = result->_contribution->getSector();

        const RectangleF* destRect = getInnerRectangle(_width, _height,
                                                       _tileSector,
                                                       *imageSector);

        //TEST MADRID
        //      if (_tileSector.contains(Angle::fromDegrees(40.41677540051771), Angle::fromDegrees(-3.7037901976145804))){
        //      printf("TS: %s\nIS: %s\nR: %s\n",_tileSector.description().c_str(),
        //             imageSector->description().c_str(),
        //             rect->description().c_str());
        //      }

        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          destRect->_x, destRect->_y,
                          destRect->_width, destRect->_height,
                          alpha);

        delete destRect;
      }
    }
  }
  _imageId = imageId;

  canvas->createImage(new ComposerImageListener(this), true);

  delete canvas;
}

bool CompositeTileImageProvider::ComposerFrameTask::isCanceled(const G3MRenderContext* rc) {
  return false;
}

void CompositeTileImageProvider::ComposerFrameTask::execute(const G3MRenderContext* rc) {
  _composer->mixResult();
}

void CompositeTileImageProvider::Composer::imageCreated(const IImage* image) {
  const CompositeTileImageContribution* compositeContribution = _compositeContribution;
  _compositeContribution = NULL; // the _compositeContribution ownership moved to the listener
  _listener->imageCreated(_tileId,
                          image,
                          _imageId,
                          compositeContribution);
  cleanUp();
}

void CompositeTileImageProvider::Composer::stepDone() {
  _stepsDone++;
  if (_stepsDone == _contributionsSize) {
    done();
  }
}

void CompositeTileImageProvider::Composer::imageCreated(const std::string&           tileId,
                                                        const IImage*                image,
                                                        const std::string&           imageId,
                                                        const TileImageContribution* contribution,
                                                        const int                    index) {
#warning DEBUG MEMORY
  //  TileImageContribution::retainContribution(contribution);
  _results[index] = ChildResult::image(image, imageId, contribution);
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationError(const std::string& error,
                                                              const int          index) {
  _results[index] = ChildResult::error(error);
  _anyError = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationCanceled(const int index) {
  _results[index] = ChildResult::cancelation();
  _anyCancelation = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::cancel(const std::string& tileId) {
  _canceled = true;
  _compositeTileImageProvider->cancelChildren(tileId, _compositeContribution);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreated(const std::string&           tileId,
                                                                      const IImage*                image,
                                                                      const std::string&           imageId,
                                                                      const TileImageContribution* contribution) {
  _composer->imageCreated(tileId, image, imageId, contribution, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationError(const std::string& tileId,
                                                                            const std::string& error) {
  _composer->imageCreationError(error, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationCanceled(const std::string& tileId) {
  _composer->imageCreationCanceled(_index);
}

void CompositeTileImageProvider::create(const Tile* tile,
                                        const TileImageContribution* contribution,
                                        const Vector2I& resolution,
                                        long long tileDownloadPriority,
                                        bool logDownloadActivity,
                                        TileImageListener* listener,
                                        bool deleteListener,
                                        FrameTasksExecutor* frameTasksExecutor) {

  const CompositeTileImageContribution* compositeContribution = (const CompositeTileImageContribution*) contribution;

  const std::string tileId = tile->_id;

  Composer* composer = new Composer(resolution._x,
                                    resolution._y,
                                    this,
                                    tileId,
                                    tile->_sector,
                                    listener,
                                    deleteListener,
                                    compositeContribution,
                                    frameTasksExecutor);

  _composers[ tileId ] = composer;

  const int contributionsSize = compositeContribution->size();
  for (int i = 0; i < contributionsSize; i++) {
    const CompositeTileImageContribution::ChildContribution* childContribution = compositeContribution->get(i);

    TileImageProvider* child = _children[ childContribution->_childIndex ];

#warning DEBUG MEMORY
    childContribution->_contribution->_retain();

    child->create(tile,
                  childContribution->_contribution,
                  resolution,
                  tileDownloadPriority,
                  logDownloadActivity,
                  new ChildTileImageListener(composer, i),
                  true,
                  frameTasksExecutor);
  }
}

void CompositeTileImageProvider::cancel(const std::string& tileId) {
#ifdef C_CODE
  if (_composers.find(tileId) != _composers.end()) {
    Composer* composer = _composers[tileId];
    composer->cancel(tileId);
    _composers.erase(tileId);
  }
#endif
#ifdef JAVA_CODE
  final Composer composer = _composers.remove(tileId);
  if (composer != null) {
    composer.cancel(tileId);
  }
#endif
}

void CompositeTileImageProvider::composerDone(Composer* composer) {
  _composers.erase( composer->_tileId );
  composer->_release();
}

void CompositeTileImageProvider::cancelChildren(const std::string& tileId,
                                                const CompositeTileImageContribution* compositeContribution) {
  const int contributionsSize = compositeContribution->size();

  // store all the indexes before calling child->cancel().
  // child->cancel() can force the deletion of the builder (and in order the deletion of compositeContribution)
  int* indexes = new int[contributionsSize];
  for (int i = 0; i < contributionsSize; i++) {
    indexes[i] = compositeContribution->get(i)->_childIndex;
  }

  for (int i = 0; i < contributionsSize; i++) {
    TileImageProvider* child = _children[ indexes[i] ];
    child->cancel(tileId);
  }

  delete [] indexes;
}
<commit_msg>Tile's image creation refactoring - NOT YET USABLE<commit_after>//
//  CompositeTileImageProvider.cpp
//  G3MiOSSDK
//
//  Created by Diego Gomez Deck on 4/23/14.
//
//

#include "CompositeTileImageProvider.hpp"
#include "TileImageListener.hpp"
#include "Tile.hpp"
#include "CompositeTileImageContribution.hpp"
#include "IFactory.hpp"
#include "ICanvas.hpp"
#include "IImage.hpp"
#include "FrameTasksExecutor.hpp"

CompositeTileImageProvider::~CompositeTileImageProvider() {
  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    child->_release();
  }
#ifdef JAVA_CODE
  super.dispose();
#endif
}

const TileImageContribution* CompositeTileImageProvider::contribution(const Tile* tile) {
  std::vector<const CompositeTileImageContribution::ChildContribution*> childrenContributions;

  for (int i = 0; i < _childrenSize; i++) {
    TileImageProvider* child = _children[i];
    const TileImageContribution* childContribution = child->contribution(tile);
    if (childContribution != NULL) {
      // ignore previous contributions, they are covered by the current fullCoverage & Opaque contribution.
      const int childrenContributionsSize = childrenContributions.size();
      if ((childrenContributionsSize > 0) &&
          childContribution->isFullCoverageAndOpaque()) {
        for (int j = 0; j < childrenContributionsSize; j++) {
          const CompositeTileImageContribution::ChildContribution* previousContribution = childrenContributions[j];
#ifdef C_CODE
          delete previousContribution;
#endif
#ifdef JAVA_CODE
          previousContribution.dispose();
#endif
        }
        childrenContributions.clear();
      }

      childrenContributions.push_back( new CompositeTileImageContribution::ChildContribution(i, childContribution) );
    }
  }

  return CompositeTileImageContribution::create(childrenContributions);
}

CompositeTileImageProvider::ChildResult::ChildResult(const bool                   isError,
                                                     const bool                   isCanceled,
                                                     const IImage*                image,
                                                     const std::string&           imageId,
                                                     const TileImageContribution* contribution,
                                                     const std::string&           error) :
_isError(isError),
_isCanceled(isCanceled),
_image(image),
_imageId(imageId),
_contribution(contribution),
_error(error)
{
  //  TileImageContribution::retainContribution(_contribution);
}

CompositeTileImageProvider::ChildResult::~ChildResult() {
  delete _image;

#warning DEBUG MEMORY
  TileImageContribution::releaseContribution(_contribution);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::image(const IImage*                image,
                                                                                const std::string&           imageId,
                                                                                const TileImageContribution* contribution) {
  return new CompositeTileImageProvider::ChildResult(false ,       // isError
                                                     false,        // isCanceled
                                                     image,
                                                     imageId,
                                                     contribution,
                                                     ""            // error
                                                     );
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::error(const std::string& error) {
  return new CompositeTileImageProvider::ChildResult(true,  // isError
                                                     false, // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     error);
}

const CompositeTileImageProvider::ChildResult* CompositeTileImageProvider::ChildResult::cancelation() {
  return new CompositeTileImageProvider::ChildResult(false, // isError
                                                     true,  // isCanceled
                                                     NULL,  // image
                                                     "",    // imageId
                                                     NULL,  // contribution
                                                     ""     // error
                                                     );
}

CompositeTileImageProvider::Composer::Composer(int width,
                                               int height,
                                               CompositeTileImageProvider* compositeTileImageProvider,
                                               const std::string& tileId,
                                               const Sector& tileSector,
                                               TileImageListener* listener,
                                               bool deleteListener,
                                               const CompositeTileImageContribution* compositeContribution,
                                               FrameTasksExecutor* frameTasksExecutor) :
_width(width),
_height(height),
_compositeTileImageProvider(compositeTileImageProvider),
_tileId(tileId),
_listener(listener),
_deleteListener(deleteListener),
_compositeContribution(compositeContribution),
_contributionsSize( compositeContribution->size() ),
_frameTasksExecutor(frameTasksExecutor),
_stepsDone(0),
_anyError(false),
_anyCancelation(false),
_canceled(false),
_tileSector(tileSector)
{
#warning DEBUG MEMORY
  //  TileImageContribution::retainContribution(_compositeContribution);
  for (int i = 0; i < _contributionsSize; i++) {
    _results.push_back( NULL );
  }
}

CompositeTileImageProvider::Composer::~Composer() {
  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    delete result;
  }

  TileImageContribution::releaseContribution(_compositeContribution);

#ifdef JAVA_CODE
  super.dispose();
#endif
}

void CompositeTileImageProvider::Composer::cleanUp() {
  if (_deleteListener) {
    delete _listener;
    _listener = NULL;
  }

  _compositeTileImageProvider->composerDone(this);
}

void CompositeTileImageProvider::Composer::done() {
  if (_canceled) {
    cleanUp();
    return;
  }

  if (_contributionsSize == 1) {
    const ChildResult* singleResult = _results[0];

    if (singleResult->_isError) {
      _listener->imageCreationError(_tileId,
                                    singleResult->_error);
    }
    else if (singleResult->_isCanceled) {
      _listener->imageCreationCanceled(_tileId);
    }
    else {
      _listener->imageCreated(singleResult->_imageId,
                              singleResult->_image->shallowCopy(),
                              singleResult->_imageId,
                              singleResult->_contribution);
    }

    cleanUp();
  }
  else {
    if (_anyError) {
      std::string composedError = "";
      for (int i = 0; i < _contributionsSize; i++) {
        const ChildResult* childResult = _results[i];
        if (childResult->_isError) {
          composedError += childResult->_error + " ";
        }
      }

      _listener->imageCreationError(_tileId,
                                    composedError);

      cleanUp();
    }
    else if (_anyCancelation) {
      _listener->imageCreationCanceled(_tileId);
      cleanUp();
    }
    else {
      //      ICanvas* canvas = IFactory::instance()->createCanvas();
      //
      //      canvas->initialize(_width, _height);
      //
      //      std::string imageId = "";
      //
      //      for (int i = 0; i < _contributionsSize; i++) {
      //       const ChildResult* result = _results[i];
      //
      //        imageId += result->_imageId + "|";
      //#warning JM: consider sector and transparency
      //        canvas->drawImage(result->_image, 0, 0);
      //      }
      //      _imageId = imageId;
      //
      //      canvas->createImage(new ComposerImageListener(this), true);
      //
      //      delete canvas;

      _frameTasksExecutor->addPreRenderTask(new ComposerFrameTask(this));
    }
  }
}

RectangleF* CompositeTileImageProvider::Composer::getInnerRectangle(int wholeSectorWidth,
                                                                    int wholeSectorHeight,
                                                                    const Sector& wholeSector,
                                                                    const Sector& innerSector) const {
  if (wholeSector.isEquals(innerSector)){
    return new RectangleF(0, 0, wholeSectorWidth, wholeSectorHeight);
  }

  const double widthFactor  = innerSector._deltaLongitude.div(wholeSector._deltaLongitude);
  const double heightFactor = innerSector._deltaLatitude.div(wholeSector._deltaLatitude);

  const Vector2D lowerUV = wholeSector.getUVCoordinates(innerSector.getNW());

  return new RectangleF((float) (lowerUV._x   * wholeSectorWidth),
                        (float) (lowerUV._y   * wholeSectorHeight),
                        (float) (widthFactor  * wholeSectorWidth),
                        (float) (heightFactor * wholeSectorHeight));
}

void CompositeTileImageProvider::Composer::mixResult() {
  if (_canceled) {
    cleanUp();
    return;
  }

  ICanvas* canvas = IFactory::instance()->createCanvas();

  canvas->initialize(_width, _height);

  std::string imageId = "";

  for (int i = 0; i < _contributionsSize; i++) {
    const ChildResult* result = _results[i];
    imageId += result->_imageId + "|";

#warning //For now, we consider the whole image will appear on the tile (no source rect needed)
    const IImage* image = result->_image;
    const float   alpha = result->_contribution->_alpha;

    if (result->_contribution->isFullCoverageAndOpaque()) {
      canvas->drawImage(image, 0, 0);
    }
    else {
      if (result->_contribution->isFullCoverage()) {
        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          0, 0,
                          _width, _height,
                          alpha);
      }
      else {
        const Sector* imageSector = result->_contribution->getSector();

        const RectangleF* destRect = getInnerRectangle(_width, _height,
                                                       _tileSector,
                                                       *imageSector);

        //TEST MADRID
        //      if (_tileSector.contains(Angle::fromDegrees(40.41677540051771), Angle::fromDegrees(-3.7037901976145804))){
        //      printf("TS: %s\nIS: %s\nR: %s\n",_tileSector.description().c_str(),
        //             imageSector->description().c_str(),
        //             rect->description().c_str());
        //      }

        canvas->drawImage(image,
                          //SRC RECT
                          0,0,
                          image->getWidth(), image->getHeight(),
                          //DEST RECT
                          destRect->_x, destRect->_y,
                          destRect->_width, destRect->_height,
                          alpha);

        delete destRect;
      }
    }
  }
  _imageId = imageId;

  canvas->createImage(new ComposerImageListener(this), true);

  delete canvas;
}

bool CompositeTileImageProvider::ComposerFrameTask::isCanceled(const G3MRenderContext* rc) {
  return false;
}

void CompositeTileImageProvider::ComposerFrameTask::execute(const G3MRenderContext* rc) {
  _composer->mixResult();
}

void CompositeTileImageProvider::Composer::imageCreated(const IImage* image) {
  const CompositeTileImageContribution* compositeContribution = _compositeContribution;
  _compositeContribution = NULL; // the _compositeContribution ownership moved to the listener
  _listener->imageCreated(_tileId,
                          image,
                          _imageId,
                          compositeContribution);
  cleanUp();
}

void CompositeTileImageProvider::Composer::stepDone() {
  _stepsDone++;
  if (_stepsDone == _contributionsSize) {
    done();
  }
}

void CompositeTileImageProvider::Composer::imageCreated(const std::string&           tileId,
                                                        const IImage*                image,
                                                        const std::string&           imageId,
                                                        const TileImageContribution* contribution,
                                                        const int                    index) {
#warning DEBUG MEMORY
  TileImageContribution::retainContribution(contribution);
  _results[index] = ChildResult::image(image, imageId, contribution);
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationError(const std::string& error,
                                                              const int          index) {
  _results[index] = ChildResult::error(error);
  _anyError = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::imageCreationCanceled(const int index) {
  _results[index] = ChildResult::cancelation();
  _anyCancelation = true;
  stepDone();
}

void CompositeTileImageProvider::Composer::cancel(const std::string& tileId) {
  _canceled = true;
  _compositeTileImageProvider->cancelChildren(tileId, _compositeContribution);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreated(const std::string&           tileId,
                                                                      const IImage*                image,
                                                                      const std::string&           imageId,
                                                                      const TileImageContribution* contribution) {
  _composer->imageCreated(tileId, image, imageId, contribution, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationError(const std::string& tileId,
                                                                            const std::string& error) {
  _composer->imageCreationError(error, _index);
}

void CompositeTileImageProvider::ChildTileImageListener::imageCreationCanceled(const std::string& tileId) {
  _composer->imageCreationCanceled(_index);
}

void CompositeTileImageProvider::create(const Tile* tile,
                                        const TileImageContribution* contribution,
                                        const Vector2I& resolution,
                                        long long tileDownloadPriority,
                                        bool logDownloadActivity,
                                        TileImageListener* listener,
                                        bool deleteListener,
                                        FrameTasksExecutor* frameTasksExecutor) {

  const CompositeTileImageContribution* compositeContribution = (const CompositeTileImageContribution*) contribution;

  const std::string tileId = tile->_id;

  Composer* composer = new Composer(resolution._x,
                                    resolution._y,
                                    this,
                                    tileId,
                                    tile->_sector,
                                    listener,
                                    deleteListener,
                                    compositeContribution,
                                    frameTasksExecutor);

  _composers[ tileId ] = composer;

  const int contributionsSize = compositeContribution->size();
  for (int i = 0; i < contributionsSize; i++) {
    const CompositeTileImageContribution::ChildContribution* childContribution = compositeContribution->get(i);

    TileImageProvider* child = _children[ childContribution->_childIndex ];

#warning DEBUG MEMORY
    childContribution->_contribution->_retain();

    child->create(tile,
                  childContribution->_contribution,
                  resolution,
                  tileDownloadPriority,
                  logDownloadActivity,
                  new ChildTileImageListener(composer, i),
                  true,
                  frameTasksExecutor);
  }
}

void CompositeTileImageProvider::cancel(const std::string& tileId) {
#ifdef C_CODE
  if (_composers.find(tileId) != _composers.end()) {
    Composer* composer = _composers[tileId];
    composer->cancel(tileId);
    _composers.erase(tileId);
  }
#endif
#ifdef JAVA_CODE
  final Composer composer = _composers.remove(tileId);
  if (composer != null) {
    composer.cancel(tileId);
  }
#endif
}

void CompositeTileImageProvider::composerDone(Composer* composer) {
  _composers.erase( composer->_tileId );
  composer->_release();
}

void CompositeTileImageProvider::cancelChildren(const std::string& tileId,
                                                const CompositeTileImageContribution* compositeContribution) {
  const int contributionsSize = compositeContribution->size();

  // store all the indexes before calling child->cancel().
  // child->cancel() can force the deletion of the builder (and in order the deletion of compositeContribution)
  int* indexes = new int[contributionsSize];
  for (int i = 0; i < contributionsSize; i++) {
    indexes[i] = compositeContribution->get(i)->_childIndex;
  }

  for (int i = 0; i < contributionsSize; i++) {
    TileImageProvider* child = _children[ indexes[i] ];
    child->cancel(tileId);
  }

  delete [] indexes;
}
<|endoftext|>


<commit_before>//
//  EllipsoidalTileTessellator.cpp
//  G3MiOSSDK
//
//  Created by Agustin Trujillo Pino on 12/07/12.
//  Copyright (c) 2012 IGO Software SL. All rights reserved.
//

#include "EllipsoidalTileTessellator.hpp"

#include "Tile.hpp"
#include "Context.hpp"
#include "IndexedMesh.hpp"
#include "TextureMapping.hpp"
#include "TexturedMesh.hpp"

#include "FloatBufferBuilder.hpp"
#include "IntBufferBuilder.hpp"

#include "FloatBufferBuilderFromCartesian3D.hpp"
#include "FloatBufferBuilderFromCartesian2D.hpp"
#include "FloatBufferBuilderFromGeodetic.hpp"
#include "SimpleFloatBufferBuilder.hpp"

Mesh* EllipsoidalTileTessellator::createMesh(const RenderContext* rc,
                                             const Tile* tile) const {

  const Sector sector = tile->getSector();
  const Planet* planet = rc->getPlanet();

  const int resolution = _resolution;
  const int resolutionMinus1 = resolution - 1;

  // create vertices coordinates
#ifdef C_CODE
  FloatBufferBuilderFromGeodetic vertices(GivenCenter, planet, sector.getCenter());
#else
  FloatBufferBuilderFromGeodetic vertices(CenterStrategy.GivenCenter, planet, sector.getCenter());
#endif
  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      Geodetic2D innerPoint = sector.getInnerPoint((double) i / resolutionMinus1,
                                                   (double) j / resolutionMinus1);

      vertices.add(innerPoint);
    }
  }

  // create indices
  IntBufferBuilder indices;
  for (int j = 0; j < resolutionMinus1; j++) {
    if (j > 0) {
      indices.add(j*resolution);
    }
    for (int i = 0; i < resolution; i++) {
      indices.add(j*resolution + i);
      indices.add(j*resolution + i + resolution);
    }
    indices.add(j*resolution + 2*resolutionMinus1);
  }

  // create skirts
  if (_skirted) {

    // compute skirt height
    const Vector3D sw = planet->toCartesian(sector.getSW());
    const Vector3D nw = planet->toCartesian(sector.getNW());
    const double skirtHeight = nw.sub(sw).length() * 0.05;

    indices.add(0);
    int posS = resolution * resolution;

    // west side
    for (int j = 0; j < resolutionMinus1; j++) {
      const Geodetic3D g(sector.getInnerPoint(0, (double)j/resolutionMinus1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(j*resolution);
      indices.add(posS++);
    }

    // south side
    for (int i = 0; i < resolutionMinus1; i++) {
      const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(resolutionMinus1*resolution + i);
      indices.add(posS++);
    }

    // east side
    for (int j = resolutionMinus1; j > 0; j--) {
      const Geodetic3D g(sector.getInnerPoint(1, (double)j/resolutionMinus1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(j*resolution + resolutionMinus1);
      indices.add(posS++);
    }

    // north side
    for (int i = resolutionMinus1; i > 0; i--) {
      const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 0),
                         -skirtHeight);
      vertices.add(g);

      indices.add(i);
      indices.add(posS++);
    }

    // last triangle
    indices.add(0);
    indices.add(resolution*resolution);
  }

  const Color *color = new Color(Color::fromRGBA((float) 0.1, (float) 0.1, (float) 0.1, (float) 1.0));

#ifdef C_CODE
  return new IndexedMesh(TriangleStrip,
                         true,
                         vertices.getCenter(),
                         vertices.create(),
                         indices.create(),
                         color);
#endif
#ifdef JAVA_CODE
  return new IndexedMesh(GLPrimitive.TriangleStrip,
                         true,
                         vertices.getCenter(),
                         vertices.create(),
                         indices.create(),
                         color);
#endif
}

IFloatBuffer* EllipsoidalTileTessellator::createUnitTextCoords() const {

  FloatBufferBuilderFromCartesian2D textCoords;

  const int resolution       = _resolution;
  const int resolutionMinus1 = resolution - 1;

  float* u = new float[resolution * resolution];
  float* v = new float[resolution * resolution];

  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      const int pos = j*resolution + i;
      u[pos] = (float) i / resolutionMinus1;
      v[pos] = (float) j / resolutionMinus1;
    }
  }

  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      const int pos = j*resolution + i;
      textCoords.add( u[pos], v[pos] );
    }
  }

  // create skirts
  if (_skirted) {
    // west side
    for (int j = 0; j < resolutionMinus1; j++) {
      const int pos = j*resolution;
      textCoords.add( u[pos], v[pos] );
    }

    // south side
    for (int i = 0; i < resolutionMinus1; i++) {
      const int pos = resolutionMinus1 * resolution + i;
      textCoords.add( u[pos], v[pos] );
    }

    // east side
    for (int j = resolutionMinus1; j > 0; j--) {
      const int pos = j*resolution + resolutionMinus1;
      textCoords.add( u[pos], v[pos] );
    }

    // north side
    for (int i = resolutionMinus1; i > 0; i--) {
      const int pos = i;
      textCoords.add( u[pos], v[pos] );
    }
  }

  // free temp memory
  delete[] u;
  delete[] v;

  return textCoords.create();
}

Mesh* EllipsoidalTileTessellator::createDebugMesh(const RenderContext* rc,
                                                  const Tile* tile) const
{
  const Sector sector = tile->getSector();
  const Planet* planet = rc->getPlanet();

  const int resolutionMinus1 = _resolution - 1;
  int posS = 0;

  // compute offset for vertices
  const Vector3D sw = planet->toCartesian(sector.getSW());
  const Vector3D nw = planet->toCartesian(sector.getNW());
  const double offset = nw.sub(sw).length() * 1e-3;

  // create vectors
#ifdef C_CODE
  FloatBufferBuilderFromGeodetic vertices(GivenCenter, planet, sector.getCenter());
#else
  FloatBufferBuilderFromGeodetic vertices(CenterStrategy.GivenCenter, planet, sector.getCenter());
#endif
  // create indices
  IntBufferBuilder indices;

  // west side
  for (int j = 0; j < resolutionMinus1; j++) {
    const Geodetic3D g(sector.getInnerPoint(0, (double)j/resolutionMinus1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // south side
  for (int i = 0; i < resolutionMinus1; i++) {
    const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // east side
  for (int j = resolutionMinus1; j > 0; j--) {
    const Geodetic3D g(sector.getInnerPoint(1, (double)j/resolutionMinus1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // north side
  for (int i = resolutionMinus1; i > 0; i--) {
    const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 0), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  const Color *color = new Color(Color::fromRGBA((float) 1.0, (float) 0, (float) 0, (float) 1.0));
  const Vector3D center = planet->toCartesian(sector.getCenter());

#ifdef C_CODE
  return new IndexedMesh(LineLoop,
                         true,
                         center,
                         vertices.create(),
                         indices.create(),
                         color);
#endif
#ifdef JAVA_CODE
  return new IndexedMesh(GLPrimitive.LineLoop,
                         true,
                         center,
                         vertices.create(),
                         indices.create(),
                         color);
#endif
}
<commit_msg>solved bug in the computation of indices in EllipsoidalTileTessellator::createMesh<commit_after>//
//  EllipsoidalTileTessellator.cpp
//  G3MiOSSDK
//
//  Created by Agustin Trujillo Pino on 12/07/12.
//  Copyright (c) 2012 IGO Software SL. All rights reserved.
//

#include "EllipsoidalTileTessellator.hpp"

#include "Tile.hpp"
#include "Context.hpp"
#include "IndexedMesh.hpp"
#include "TextureMapping.hpp"
#include "TexturedMesh.hpp"

#include "FloatBufferBuilder.hpp"
#include "IntBufferBuilder.hpp"

#include "FloatBufferBuilderFromCartesian3D.hpp"
#include "FloatBufferBuilderFromCartesian2D.hpp"
#include "FloatBufferBuilderFromGeodetic.hpp"
#include "SimpleFloatBufferBuilder.hpp"

Mesh* EllipsoidalTileTessellator::createMesh(const RenderContext* rc,
                                             const Tile* tile) const {

  const Sector sector = tile->getSector();
  const Planet* planet = rc->getPlanet();

  const int resolution = _resolution;
  const int resolutionMinus1 = resolution - 1;

  // create vertices coordinates
#ifdef C_CODE
  FloatBufferBuilderFromGeodetic vertices(GivenCenter, planet, sector.getCenter());
#else
  FloatBufferBuilderFromGeodetic vertices(CenterStrategy.GivenCenter, planet, sector.getCenter());
#endif
  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      Geodetic2D innerPoint = sector.getInnerPoint((double) i / resolutionMinus1,
                                                   (double) j / resolutionMinus1);

      vertices.add(innerPoint);
    }
  }

  // create indices
  IntBufferBuilder indices;
  for (int j = 0; j < resolutionMinus1; j++) {
    if (j > 0) {
      indices.add(j*resolution);
    }
    for (int i = 0; i < resolution; i++) {
      indices.add(j*resolution + i);
      indices.add(j*resolution + i + resolution);
    }
    indices.add(j*resolution + 2*resolution - 1);
  }

  // create skirts
  if (_skirted) {

    // compute skirt height
    const Vector3D sw = planet->toCartesian(sector.getSW());
    const Vector3D nw = planet->toCartesian(sector.getNW());
    const double skirtHeight = nw.sub(sw).length() * 0.05;

    indices.add(0);
    int posS = resolution * resolution;

    // west side
    for (int j = 0; j < resolutionMinus1; j++) {
      const Geodetic3D g(sector.getInnerPoint(0, (double)j/resolutionMinus1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(j*resolution);
      indices.add(posS++);
    }

    // south side
    for (int i = 0; i < resolutionMinus1; i++) {
      const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(resolutionMinus1*resolution + i);
      indices.add(posS++);
    }

    // east side
    for (int j = resolutionMinus1; j > 0; j--) {
      const Geodetic3D g(sector.getInnerPoint(1, (double)j/resolutionMinus1),
                         -skirtHeight);
      vertices.add(g);

      indices.add(j*resolution + resolutionMinus1);
      indices.add(posS++);
    }

    // north side
    for (int i = resolutionMinus1; i > 0; i--) {
      const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 0),
                         -skirtHeight);
      vertices.add(g);

      indices.add(i);
      indices.add(posS++);
    }

    // last triangle
    indices.add(0);
    indices.add(resolution*resolution);
  }

  const Color *color = new Color(Color::fromRGBA((float) 0.1, (float) 0.1, (float) 0.1, (float) 1.0));

#ifdef C_CODE
  return new IndexedMesh(TriangleStrip,
                         true,
                         vertices.getCenter(),
                         vertices.create(),
                         indices.create(),
                         color);
#endif
#ifdef JAVA_CODE
  return new IndexedMesh(GLPrimitive.TriangleStrip,
                         true,
                         vertices.getCenter(),
                         vertices.create(),
                         indices.create(),
                         color);
#endif
}

IFloatBuffer* EllipsoidalTileTessellator::createUnitTextCoords() const {

  FloatBufferBuilderFromCartesian2D textCoords;

  const int resolution       = _resolution;
  const int resolutionMinus1 = resolution - 1;

  float* u = new float[resolution * resolution];
  float* v = new float[resolution * resolution];

  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      const int pos = j*resolution + i;
      u[pos] = (float) i / resolutionMinus1;
      v[pos] = (float) j / resolutionMinus1;
    }
  }

  for (int j = 0; j < resolution; j++) {
    for (int i = 0; i < resolution; i++) {
      const int pos = j*resolution + i;
      textCoords.add( u[pos], v[pos] );
    }
  }

  // create skirts
  if (_skirted) {
    // west side
    for (int j = 0; j < resolutionMinus1; j++) {
      const int pos = j*resolution;
      textCoords.add( u[pos], v[pos] );
    }

    // south side
    for (int i = 0; i < resolutionMinus1; i++) {
      const int pos = resolutionMinus1 * resolution + i;
      textCoords.add( u[pos], v[pos] );
    }

    // east side
    for (int j = resolutionMinus1; j > 0; j--) {
      const int pos = j*resolution + resolutionMinus1;
      textCoords.add( u[pos], v[pos] );
    }

    // north side
    for (int i = resolutionMinus1; i > 0; i--) {
      const int pos = i;
      textCoords.add( u[pos], v[pos] );
    }
  }

  // free temp memory
  delete[] u;
  delete[] v;

  return textCoords.create();
}

Mesh* EllipsoidalTileTessellator::createDebugMesh(const RenderContext* rc,
                                                  const Tile* tile) const
{
  const Sector sector = tile->getSector();
  const Planet* planet = rc->getPlanet();

  const int resolutionMinus1 = _resolution - 1;
  int posS = 0;

  // compute offset for vertices
  const Vector3D sw = planet->toCartesian(sector.getSW());
  const Vector3D nw = planet->toCartesian(sector.getNW());
  const double offset = nw.sub(sw).length() * 1e-3;

  // create vectors
#ifdef C_CODE
  FloatBufferBuilderFromGeodetic vertices(GivenCenter, planet, sector.getCenter());
#else
  FloatBufferBuilderFromGeodetic vertices(CenterStrategy.GivenCenter, planet, sector.getCenter());
#endif
  // create indices
  IntBufferBuilder indices;

  // west side
  for (int j = 0; j < resolutionMinus1; j++) {
    const Geodetic3D g(sector.getInnerPoint(0, (double)j/resolutionMinus1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // south side
  for (int i = 0; i < resolutionMinus1; i++) {
    const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // east side
  for (int j = resolutionMinus1; j > 0; j--) {
    const Geodetic3D g(sector.getInnerPoint(1, (double)j/resolutionMinus1), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  // north side
  for (int i = resolutionMinus1; i > 0; i--) {
    const Geodetic3D g(sector.getInnerPoint((double)i/resolutionMinus1, 0), offset);

    vertices.add(g);
    indices.add(posS++);
  }

  const Color *color = new Color(Color::fromRGBA((float) 1.0, (float) 0, (float) 0, (float) 1.0));
  const Vector3D center = planet->toCartesian(sector.getCenter());

#ifdef C_CODE
  return new IndexedMesh(LineLoop,
                         true,
                         center,
                         vertices.create(),
                         indices.create(),
                         color);
#endif
#ifdef JAVA_CODE
  return new IndexedMesh(GLPrimitive.LineLoop,
                         true,
                         center,
                         vertices.create(),
                         indices.create(),
                         color);
#endif
}
<|endoftext|>


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

#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"

#include <string>
#include <vector>

#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/common/pref_names.h"
#include "chromeos/cryptohome/cryptohome_library.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"

namespace {
const char kServiceScopeGetUserInfo[] =
    "https://www.googleapis.com/auth/userinfo.email";
}  // namespace

namespace chromeos {

// A wrapper for the consumer passed to StartRequest, which doesn't call
// through to the target Consumer unless the refresh token validation is
// complete.  Additionally implements the Request interface, so that it
// can be passed back to the caller and directly deleted when cancelling
// the request.
class DeviceOAuth2TokenService::ValidatingConsumer
    : public OAuth2TokenService::Consumer,
      public OAuth2TokenService::Request,
      public gaia::GaiaOAuthClient::Delegate {
 public:
  explicit ValidatingConsumer(DeviceOAuth2TokenService* token_service,
                              Consumer* consumer);
  virtual ~ValidatingConsumer();

  void StartValidation(scoped_ptr<Request> request);

  // OAuth2TokenService::Consumer
  virtual void OnGetTokenSuccess(
      const Request* request,
      const std::string& access_token,
      const base::Time& expiration_time) OVERRIDE;
  virtual void OnGetTokenFailure(
      const Request* request,
      const GoogleServiceAuthError& error) OVERRIDE;

  // gaia::GaiaOAuthClient::Delegate implementation.
  virtual void OnRefreshTokenResponse(const std::string& access_token,
                                      int expires_in_seconds) OVERRIDE;
  virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info)
      OVERRIDE;
  virtual void OnOAuthError() OVERRIDE;
  virtual void OnNetworkError(int response_code) OVERRIDE;

 private:
  void RefreshTokenIsValid(bool is_valid);
  void InformConsumer();

  DeviceOAuth2TokenService* token_service_;
  Consumer* consumer_;
  scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;

  // We don't know which will complete first: the validation or the token
  // minting.  So, we need to cache the results so the final callback can
  // take action.

  // RefreshTokenValidationConsumer results
  bool token_validation_done_;
  bool token_is_valid_;

  // The request instance returned by OAuth2TokenService, which we're
  // wrapping.  If the this object is deleted, |request_| will also be
  // deleted and the OAuth2TokenService won't call back on this object.
  scoped_ptr<OAuth2TokenService::Request> request_;

  // OAuth2TokenService::Consumer results
  bool token_fetch_done_;
  std::string access_token_;
  base::Time expiration_time_;
  scoped_ptr<GoogleServiceAuthError> error_;
};

DeviceOAuth2TokenService::ValidatingConsumer::ValidatingConsumer(
    DeviceOAuth2TokenService* token_service,
    Consumer* consumer)
        : token_service_(token_service),
          consumer_(consumer),
          token_validation_done_(false),
          token_is_valid_(false),
          token_fetch_done_(false) {
}

DeviceOAuth2TokenService::ValidatingConsumer::~ValidatingConsumer() {
}

void DeviceOAuth2TokenService::ValidatingConsumer::StartValidation(
    scoped_ptr<Request> request) {
  DCHECK(!gaia_oauth_client_);
  request_ = request.Pass();
  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
      g_browser_process->system_request_context()));

  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
  gaia::OAuthClientInfo client_info;
  client_info.client_id = gaia_urls->oauth2_chrome_client_id();
  client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();

  gaia_oauth_client_->RefreshToken(
      client_info,
      token_service_->GetRefreshToken(),
      std::vector<std::string>(1, kServiceScopeGetUserInfo),
      token_service_->max_refresh_token_validation_retries_,
      this);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnRefreshTokenResponse(
    const std::string& access_token,
    int expires_in_seconds) {
  gaia_oauth_client_->GetTokenInfo(
      access_token,
      token_service_->max_refresh_token_validation_retries_,
      this);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenInfoResponse(
    scoped_ptr<DictionaryValue> token_info) {
  std::string gaia_robot_id;
  token_info->GetString("email", &gaia_robot_id);

  std::string policy_robot_id = token_service_->GetRobotAccountId();

  if (policy_robot_id == gaia_robot_id) {
    RefreshTokenIsValid(true);
  } else {
    if (gaia_robot_id.empty()) {
      LOG(WARNING) << "Device service account owner in policy is empty.";
    } else {
      LOG(INFO) << "Device service account owner in policy does not match "
                << "refresh token owner \"" << gaia_robot_id << "\".";
    }
    RefreshTokenIsValid(false);
  }
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnOAuthError() {
  RefreshTokenIsValid(false);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnNetworkError(
    int response_code) {
  RefreshTokenIsValid(false);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenSuccess(
      const Request* request,
      const std::string& access_token,
      const base::Time& expiration_time) {
  token_fetch_done_ = true;
  access_token_ = access_token;
  expiration_time_ = expiration_time;
  if (token_validation_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenFailure(
      const Request* request,
      const GoogleServiceAuthError& error) {
  token_fetch_done_ = true;
  error_.reset(new GoogleServiceAuthError(error.state()));
  if (token_validation_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::RefreshTokenIsValid(
    bool is_valid) {
  token_validation_done_ = true;
  token_is_valid_ = is_valid;
  if (token_fetch_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::InformConsumer() {
  DCHECK(token_fetch_done_);
  DCHECK(token_validation_done_);
  token_service_->OnValidationComplete(token_is_valid_);
  // Note: this object (which is also the Request instance) may be deleted in
  // these consumer callbacks, so the callbacks must be the last line executed.
  if (!token_is_valid_) {
    consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(
        GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
  } else if (error_) {
    consumer_->OnGetTokenFailure(this, *error_.get());
  } else {
    consumer_->OnGetTokenSuccess(this, access_token_, expiration_time_);
  }
}

DeviceOAuth2TokenService::DeviceOAuth2TokenService(
    net::URLRequestContextGetter* getter,
    PrefService* local_state)
    : refresh_token_is_valid_(false),
      max_refresh_token_validation_retries_(3),
      url_request_context_getter_(getter),
      local_state_(local_state) {
}

DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
}

net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
  return url_request_context_getter_.get();
}

scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
    const OAuth2TokenService::ScopeSet& scopes,
    OAuth2TokenService::Consumer* consumer) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  if (refresh_token_is_valid_) {
    return OAuth2TokenService::StartRequest(scopes, consumer).Pass();
  } else {
    scoped_ptr<ValidatingConsumer> validating_consumer(
        new ValidatingConsumer(this, consumer));

    scoped_ptr<Request> request = OAuth2TokenService::StartRequest(
        scopes, validating_consumer.get());
    validating_consumer->StartValidation(request.Pass());
    return validating_consumer.PassAs<Request>();
  }
}

void DeviceOAuth2TokenService::OnValidationComplete(
    bool refresh_token_is_valid) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  refresh_token_is_valid_ = refresh_token_is_valid;
}

// static
void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
  registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
                               std::string());
}

void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
    const std::string& refresh_token) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  std::string encrypted_refresh_token =
      CryptohomeLibrary::Get()->EncryptWithSystemSalt(refresh_token);

  local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
                          encrypted_refresh_token);
}

std::string DeviceOAuth2TokenService::GetRefreshToken() {
  if (refresh_token_.empty()) {
    std::string encrypted_refresh_token =
        local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);

    refresh_token_ = CryptohomeLibrary::Get()->DecryptWithSystemSalt(
        encrypted_refresh_token);
  }
  return refresh_token_;
}

std::string DeviceOAuth2TokenService::GetRobotAccountId() {
  policy::BrowserPolicyConnector* connector =
      g_browser_process->browser_policy_connector();
  if (connector)
    return connector->GetDeviceCloudPolicyManager()->GetRobotAccountId();
  return std::string();
}

}  // namespace chromeos
<commit_msg>Fix crash in Kiosk Apps identity API with robot accounts.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"

#include <string>
#include <vector>

#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
#include "chrome/common/pref_names.h"
#include "chromeos/cryptohome/cryptohome_library.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"

namespace {
const char kServiceScopeGetUserInfo[] =
    "https://www.googleapis.com/auth/userinfo.email";
}  // namespace

namespace chromeos {

// A wrapper for the consumer passed to StartRequest, which doesn't call
// through to the target Consumer unless the refresh token validation is
// complete.  Additionally implements the Request interface, so that it
// can be passed back to the caller and directly deleted when cancelling
// the request.
class DeviceOAuth2TokenService::ValidatingConsumer
    : public OAuth2TokenService::Consumer,
      public OAuth2TokenService::Request,
      public gaia::GaiaOAuthClient::Delegate {
 public:
  explicit ValidatingConsumer(DeviceOAuth2TokenService* token_service,
                              Consumer* consumer);
  virtual ~ValidatingConsumer();

  void StartValidation(scoped_ptr<Request> request);

  // OAuth2TokenService::Consumer
  virtual void OnGetTokenSuccess(
      const Request* request,
      const std::string& access_token,
      const base::Time& expiration_time) OVERRIDE;
  virtual void OnGetTokenFailure(
      const Request* request,
      const GoogleServiceAuthError& error) OVERRIDE;

  // gaia::GaiaOAuthClient::Delegate implementation.
  virtual void OnRefreshTokenResponse(const std::string& access_token,
                                      int expires_in_seconds) OVERRIDE;
  virtual void OnGetTokenInfoResponse(scoped_ptr<DictionaryValue> token_info)
      OVERRIDE;
  virtual void OnOAuthError() OVERRIDE;
  virtual void OnNetworkError(int response_code) OVERRIDE;

 private:
  void RefreshTokenIsValid(bool is_valid);
  void InformConsumer();

  DeviceOAuth2TokenService* token_service_;
  Consumer* consumer_;
  scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;

  // We don't know which will complete first: the validation or the token
  // minting.  So, we need to cache the results so the final callback can
  // take action.

  // RefreshTokenValidationConsumer results
  bool token_validation_done_;
  bool token_is_valid_;

  // The request instance returned by OAuth2TokenService, which we're
  // wrapping.  If the this object is deleted, |request_| will also be
  // deleted and the OAuth2TokenService won't call back on this object.
  scoped_ptr<OAuth2TokenService::Request> request_;

  // OAuth2TokenService::Consumer results
  bool token_fetch_done_;
  std::string access_token_;
  base::Time expiration_time_;
  scoped_ptr<GoogleServiceAuthError> error_;
};

DeviceOAuth2TokenService::ValidatingConsumer::ValidatingConsumer(
    DeviceOAuth2TokenService* token_service,
    Consumer* consumer)
        : token_service_(token_service),
          consumer_(consumer),
          token_validation_done_(false),
          token_is_valid_(false),
          token_fetch_done_(false) {
}

DeviceOAuth2TokenService::ValidatingConsumer::~ValidatingConsumer() {
}

void DeviceOAuth2TokenService::ValidatingConsumer::StartValidation(
    scoped_ptr<Request> request) {
  DCHECK(!gaia_oauth_client_);
  request_ = request.Pass();
  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
      g_browser_process->system_request_context()));

  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
  gaia::OAuthClientInfo client_info;
  client_info.client_id = gaia_urls->oauth2_chrome_client_id();
  client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();

  gaia_oauth_client_->RefreshToken(
      client_info,
      token_service_->GetRefreshToken(),
      std::vector<std::string>(1, kServiceScopeGetUserInfo),
      token_service_->max_refresh_token_validation_retries_,
      this);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnRefreshTokenResponse(
    const std::string& access_token,
    int expires_in_seconds) {
  gaia_oauth_client_->GetTokenInfo(
      access_token,
      token_service_->max_refresh_token_validation_retries_,
      this);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenInfoResponse(
    scoped_ptr<DictionaryValue> token_info) {
  std::string gaia_robot_id;
  token_info->GetString("email", &gaia_robot_id);

  std::string policy_robot_id = token_service_->GetRobotAccountId();

  if (policy_robot_id == gaia_robot_id) {
    RefreshTokenIsValid(true);
  } else {
    if (gaia_robot_id.empty()) {
      LOG(WARNING) << "Device service account owner in policy is empty.";
    } else {
      LOG(INFO) << "Device service account owner in policy does not match "
                << "refresh token owner \"" << gaia_robot_id << "\".";
    }
    RefreshTokenIsValid(false);
  }
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnOAuthError() {
  RefreshTokenIsValid(false);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnNetworkError(
    int response_code) {
  RefreshTokenIsValid(false);
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenSuccess(
      const Request* request,
      const std::string& access_token,
      const base::Time& expiration_time) {
  token_fetch_done_ = true;
  access_token_ = access_token;
  expiration_time_ = expiration_time;
  if (token_validation_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::OnGetTokenFailure(
      const Request* request,
      const GoogleServiceAuthError& error) {
  token_fetch_done_ = true;
  error_.reset(new GoogleServiceAuthError(error.state()));
  if (token_validation_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::RefreshTokenIsValid(
    bool is_valid) {
  token_validation_done_ = true;
  token_is_valid_ = is_valid;
  if (token_fetch_done_)
    InformConsumer();
}

void DeviceOAuth2TokenService::ValidatingConsumer::InformConsumer() {
  DCHECK(token_fetch_done_);
  DCHECK(token_validation_done_);
  token_service_->OnValidationComplete(token_is_valid_);
  // Note: this object (which is also the Request instance) may be deleted in
  // these consumer callbacks, so the callbacks must be the last line executed.
  // Also, make copies of the parameters passed to the consumer to avoid invalid
  // memory accesses when the consumer deletes |this| immediately.
  if (!token_is_valid_) {
    consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(
        GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
  } else if (error_) {
    GoogleServiceAuthError error_copy = *error_;
    consumer_->OnGetTokenFailure(this, error_copy);
  } else {
    std::string access_token_copy = access_token_;
    base::Time expiration_time_copy = expiration_time_;
    consumer_->OnGetTokenSuccess(this, access_token_copy, expiration_time_copy);
  }
}

DeviceOAuth2TokenService::DeviceOAuth2TokenService(
    net::URLRequestContextGetter* getter,
    PrefService* local_state)
    : refresh_token_is_valid_(false),
      max_refresh_token_validation_retries_(3),
      url_request_context_getter_(getter),
      local_state_(local_state) {
}

DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
}

net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
  return url_request_context_getter_.get();
}

scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
    const OAuth2TokenService::ScopeSet& scopes,
    OAuth2TokenService::Consumer* consumer) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  if (refresh_token_is_valid_) {
    return OAuth2TokenService::StartRequest(scopes, consumer).Pass();
  } else {
    scoped_ptr<ValidatingConsumer> validating_consumer(
        new ValidatingConsumer(this, consumer));

    scoped_ptr<Request> request = OAuth2TokenService::StartRequest(
        scopes, validating_consumer.get());
    validating_consumer->StartValidation(request.Pass());
    return validating_consumer.PassAs<Request>();
  }
}

void DeviceOAuth2TokenService::OnValidationComplete(
    bool refresh_token_is_valid) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  refresh_token_is_valid_ = refresh_token_is_valid;
}

// static
void DeviceOAuth2TokenService::RegisterPrefs(PrefRegistrySimple* registry) {
  registry->RegisterStringPref(prefs::kDeviceRobotAnyApiRefreshToken,
                               std::string());
}

void DeviceOAuth2TokenService::SetAndSaveRefreshToken(
    const std::string& refresh_token) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  std::string encrypted_refresh_token =
      CryptohomeLibrary::Get()->EncryptWithSystemSalt(refresh_token);

  local_state_->SetString(prefs::kDeviceRobotAnyApiRefreshToken,
                          encrypted_refresh_token);
}

std::string DeviceOAuth2TokenService::GetRefreshToken() {
  if (refresh_token_.empty()) {
    std::string encrypted_refresh_token =
        local_state_->GetString(prefs::kDeviceRobotAnyApiRefreshToken);

    refresh_token_ = CryptohomeLibrary::Get()->DecryptWithSystemSalt(
        encrypted_refresh_token);
  }
  return refresh_token_;
}

std::string DeviceOAuth2TokenService::GetRobotAccountId() {
  policy::BrowserPolicyConnector* connector =
      g_browser_process->browser_policy_connector();
  if (connector)
    return connector->GetDeviceCloudPolicyManager()->GetRobotAccountId();
  return std::string();
}

}  // namespace chromeos
<|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 "base/stringprintf.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_webstore_private_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
#include "content/common/notification_service.h"
#include "net/base/mock_host_resolver.h"

// A base class for tests below.
class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitchASCII(switches::kAppsGalleryURL,
        "http://www.example.com");
  }

  void SetUpInProcessBrowserTestFixture() OVERRIDE {
    // Start up the test server and get us ready for calling the install
    // API functions.
    host_resolver()->AddRule("www.example.com", "127.0.0.1");
    ASSERT_TRUE(test_server()->Start());
    BeginInstallWithManifestFunction::SetIgnoreUserGestureForTests(true);
    BeginInstallWithManifestFunction::SetAutoConfirmForTests(true);
    ExtensionInstallUI::DisableFailureUIForTests();
  }

 protected:
  // Returns a test server URL, but with host 'www.example.com' so it matches
  // the web store app's extent that we set up via command line flags.
  GURL GetTestServerURL(const std::string& path) {
    GURL url = test_server()->GetURL(
        std::string("files/extensions/api_test/webstore_private/") + path);

    // Replace the host with 'www.example.com' so it matches the web store
    // app's extent.
    GURL::Replacements replace_host;
    std::string host_str("www.example.com");
    replace_host.SetHostStr(host_str);

    return url.ReplaceComponents(replace_host);
  }

  // Navigates to |page| and runs the Extension API test there. Any downloads
  // of extensions will return the contents of |crx_file|.
  bool RunInstallTest(const std::string& page, const std::string& crx_file) {
    GURL crx_url = GetTestServerURL(crx_file);
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryUpdateURL, crx_url.spec());

    GURL page_url = GetTestServerURL(page);
    return RunPageTest(page_url.spec());
  }

  ExtensionService* service() {
    return browser()->profile()->GetExtensionService();
  }
};

// TODO(asargent) - flaky; see crbug.com/80606.
// Test cases where the user accepts the install confirmation dialog.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, FLAKY_InstallAccepted) {
  ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
}

// Tests passing a localized name.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallLocalized) {
  ASSERT_TRUE(RunInstallTest("localized.html", "localized_extension.crx"));
}

// Now test the case where the user cancels the confirmation dialog.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallCancelled) {
  BeginInstallWithManifestFunction::SetAutoConfirmForTests(false);
  ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx"));
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallNoGesture) {
  BeginInstallFunction::SetIgnoreUserGestureForTests(false);
  ASSERT_TRUE(RunInstallTest("no_user_gesture.html", "extension.crx"));
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       IncorrectManifest1) {
  ui_test_utils::WindowedNotificationObserver observer(
      NotificationType::EXTENSION_INSTALL_ERROR,
      NotificationService::AllSources());
  ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx"));
  observer.Wait();
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       IncorrectManifest2) {
  ui_test_utils::WindowedNotificationObserver observer(
      NotificationType::EXTENSION_INSTALL_ERROR,
      NotificationService::AllSources());
  ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx"));
  observer.Wait();
}
<commit_msg>Remove flaky label from a ExtensionWebstorePrivateApiTest test<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 "base/stringprintf.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_webstore_private_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
#include "content/common/notification_service.h"
#include "net/base/mock_host_resolver.h"

// A base class for tests below.
class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitchASCII(switches::kAppsGalleryURL,
        "http://www.example.com");
  }

  void SetUpInProcessBrowserTestFixture() OVERRIDE {
    // Start up the test server and get us ready for calling the install
    // API functions.
    host_resolver()->AddRule("www.example.com", "127.0.0.1");
    ASSERT_TRUE(test_server()->Start());
    BeginInstallWithManifestFunction::SetIgnoreUserGestureForTests(true);
    BeginInstallWithManifestFunction::SetAutoConfirmForTests(true);
    ExtensionInstallUI::DisableFailureUIForTests();
  }

 protected:
  // Returns a test server URL, but with host 'www.example.com' so it matches
  // the web store app's extent that we set up via command line flags.
  GURL GetTestServerURL(const std::string& path) {
    GURL url = test_server()->GetURL(
        std::string("files/extensions/api_test/webstore_private/") + path);

    // Replace the host with 'www.example.com' so it matches the web store
    // app's extent.
    GURL::Replacements replace_host;
    std::string host_str("www.example.com");
    replace_host.SetHostStr(host_str);

    return url.ReplaceComponents(replace_host);
  }

  // Navigates to |page| and runs the Extension API test there. Any downloads
  // of extensions will return the contents of |crx_file|.
  bool RunInstallTest(const std::string& page, const std::string& crx_file) {
    GURL crx_url = GetTestServerURL(crx_file);
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kAppsGalleryUpdateURL, crx_url.spec());

    GURL page_url = GetTestServerURL(page);
    return RunPageTest(page_url.spec());
  }

  ExtensionService* service() {
    return browser()->profile()->GetExtensionService();
  }
};

// Test cases where the user accepts the install confirmation dialog.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallAccepted) {
  ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
}

// Tests passing a localized name.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallLocalized) {
  ASSERT_TRUE(RunInstallTest("localized.html", "localized_extension.crx"));
}

// Now test the case where the user cancels the confirmation dialog.
IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallCancelled) {
  BeginInstallWithManifestFunction::SetAutoConfirmForTests(false);
  ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx"));
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallNoGesture) {
  BeginInstallFunction::SetIgnoreUserGestureForTests(false);
  ASSERT_TRUE(RunInstallTest("no_user_gesture.html", "extension.crx"));
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       IncorrectManifest1) {
  ui_test_utils::WindowedNotificationObserver observer(
      NotificationType::EXTENSION_INSTALL_ERROR,
      NotificationService::AllSources());
  ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx"));
  observer.Wait();
}

IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
                       IncorrectManifest2) {
  ui_test_utils::WindowedNotificationObserver observer(
      NotificationType::EXTENSION_INSTALL_ERROR,
      NotificationService::AllSources());
  ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx"));
  observer.Wait();
}
<|endoftext|>


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

#include "chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h"

#include "base/compiler_specific.h"
#include "chrome/browser/net/url_request_context_getter.h"
#include "chrome/browser/profile.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/client_socket_factory.h"
#include "net/url_request/url_request_context.h"

namespace notifier {

namespace {

// Convert values from <errno.h> to values from "net/base/net_errors.h"
int MapPosixError(int err) {
  // There are numerous posix error codes, but these are the ones we thus far
  // find interesting.
  switch (err) {
    case EAGAIN:
#if EWOULDBLOCK != EAGAIN
    case EWOULDBLOCK:
#endif
      return net::ERR_IO_PENDING;
    case ENETDOWN:
      return net::ERR_INTERNET_DISCONNECTED;
    case ETIMEDOUT:
      return net::ERR_TIMED_OUT;
    case ECONNRESET:
    case ENETRESET:  // Related to keep-alive
      return net::ERR_CONNECTION_RESET;
    case ECONNABORTED:
      return net::ERR_CONNECTION_ABORTED;
    case ECONNREFUSED:
      return net::ERR_CONNECTION_REFUSED;
    case EHOSTUNREACH:
    case ENETUNREACH:
      return net::ERR_ADDRESS_UNREACHABLE;
    case EADDRNOTAVAIL:
      return net::ERR_ADDRESS_INVALID;
    case 0:
      return net::OK;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return net::ERR_FAILED;
  }
}

}

SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
  return new SSLSocketAdapter(socket);
}

SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
    : AsyncSocketAdapter(socket),
      ignore_bad_cert_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(
        connected_callback_(this, &SSLSocketAdapter::OnConnected)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
        io_callback_(this, &SSLSocketAdapter::OnIO)),
      ssl_connected_(false),
      state_(STATE_NONE) {
  socket_ = new TransportSocket(socket, this);
}

int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
  DCHECK(!restartable);

  // SSLConfigService is not thread-safe, and the default values for SSLConfig
  // are correct for us, so we don't use the config service to initialize this
  // object.
  net::SSLConfig ssl_config;
  socket_->set_addr(talk_base::SocketAddress(hostname));
  ssl_socket_.reset(
      net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
          socket_, hostname, ssl_config));

  int result = ssl_socket_->Connect(&connected_callback_, NULL);

  if (result == net::ERR_IO_PENDING || result == net::OK) {
    return 0;
  } else {
    return result;
  }
}

int SSLSocketAdapter::Send(const void* buf, size_t len) {
  if (!ssl_connected_) {
    return AsyncSocketAdapter::Send(buf, len);
  } else {
    scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len);
    memcpy(transport_buf->data(), buf, len);

    int result = ssl_socket_->Write(transport_buf, len, NULL);
    if (result == net::ERR_IO_PENDING) {
      SetError(EWOULDBLOCK);
    }
    transport_buf = NULL;
    return result;
  }
}

int SSLSocketAdapter::Recv(void* buf, size_t len) {
  if (!ssl_connected_) {
    return AsyncSocketAdapter::Recv(buf, len);
  }

  switch (state_) {
    case STATE_NONE: {
      transport_buf_ = new net::IOBuffer(len);
      int result = ssl_socket_->Read(transport_buf_, len, &io_callback_);
      if (result >= 0) {
        memcpy(buf, transport_buf_->data(), len);
      }

      if (result == net::ERR_IO_PENDING) {
        state_ = STATE_READ;
        SetError(EWOULDBLOCK);
      } else {
        if (result < 0) {
          SetError(result);
          LOG(INFO) << "Socket error " << result;
        }
        transport_buf_ = NULL;
      }
      return result;
    }
    case STATE_READ_COMPLETE:
      memcpy(buf, transport_buf_->data(), len);
      transport_buf_ = NULL;
      state_ = STATE_NONE;
      return data_transferred_;

    case STATE_READ:
    case STATE_WRITE:
    case STATE_WRITE_COMPLETE:
      SetError(EWOULDBLOCK);
      return -1;

    default:
      NOTREACHED();
      break;
  }
  return -1;
}

void SSLSocketAdapter::OnConnected(int result) {
  if (result == net::OK) {
    ssl_connected_ = true;
    OnConnectEvent(this);
  }
}

void SSLSocketAdapter::OnIO(int result) {
  switch (state_) {
    case STATE_READ:
      state_ = STATE_READ_COMPLETE;
      data_transferred_ = result;
      AsyncSocketAdapter::OnReadEvent(this);
      break;
    case STATE_WRITE:
      state_ = STATE_WRITE_COMPLETE;
      data_transferred_ = result;
      AsyncSocketAdapter::OnWriteEvent(this);
      break;
    case STATE_NONE:
    case STATE_READ_COMPLETE:
    case STATE_WRITE_COMPLETE:
    default:
      NOTREACHED();
      break;
  }
}

void SSLSocketAdapter::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (!socket_->OnReadEvent(socket))
    AsyncSocketAdapter::OnReadEvent(socket);
}

void SSLSocketAdapter::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (!socket_->OnWriteEvent(socket))
    AsyncSocketAdapter::OnWriteEvent(socket);
}

TransportSocket::TransportSocket(talk_base::AsyncSocket* socket,
                                 SSLSocketAdapter *ssl_adapter)
    : connect_callback_(NULL),
      read_callback_(NULL),
      write_callback_(NULL),
      read_buffer_len_(0),
      write_buffer_len_(0),
      socket_(socket) {
    socket_->SignalConnectEvent.connect(this, &TransportSocket::OnConnectEvent);
}

int TransportSocket::Connect(net::CompletionCallback* callback,
                             net::LoadLog* /* load_log */) {
  connect_callback_ = callback;
  return socket_->Connect(addr_);
}

void TransportSocket::Disconnect() {
  socket_->Close();
}

bool TransportSocket::IsConnected() const {
  return (socket_->GetState() == talk_base::Socket::CS_CONNECTED);
}

bool TransportSocket::IsConnectedAndIdle() const {
  // Not implemented.
  NOTREACHED();
  return false;
}

int TransportSocket::GetPeerName(struct sockaddr* name, socklen_t* namelen) {
  talk_base::SocketAddress address = socket_->GetRemoteAddress();
  address.ToSockAddr(reinterpret_cast<sockaddr_in *>(name));
  return 0;
}

int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
                          net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!read_callback_);
  DCHECK(!read_buffer_.get());
  int result = socket_->Recv(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      read_callback_ = callback;
      read_buffer_ = buf;
      read_buffer_len_ = buf_len;
    }
  }
  return result;
}

int TransportSocket::Write(net::IOBuffer* buf, int buf_len,
                           net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!write_callback_);
  DCHECK(!write_buffer_.get());
  int result = socket_->Send(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      write_callback_ = callback;
      write_buffer_ = buf;
      write_buffer_len_ = buf_len;
    }
  }
  return result;
}

bool TransportSocket::SetReceiveBufferSize(int32 size) {
  // Not implemented.
  return false;
}

bool TransportSocket::SetSendBufferSize(int32 size) {
  // Not implemented.
  return false;
}

void TransportSocket::OnConnectEvent(talk_base::AsyncSocket * socket) {
  if (connect_callback_) {
    net::CompletionCallback *callback = connect_callback_;
    connect_callback_ = NULL;
    callback->RunWithParams(Tuple1<int>(MapPosixError(socket_->GetError())));
  }
}

bool TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (read_callback_) {
    DCHECK(read_buffer_.get());
    net::CompletionCallback* callback = read_callback_;
    scoped_refptr<net::IOBuffer> buffer = read_buffer_;
    int buffer_len = read_buffer_len_;

    read_callback_ = NULL;
    read_buffer_ = NULL;
    read_buffer_len_ = 0;

    int result = socket_->Recv(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        read_callback_ = callback;
        read_buffer_ = buffer;
        read_buffer_len_ = buffer_len;
        return true;
      }
    }
    callback->RunWithParams(Tuple1<int>(result));
    return true;
  } else {
    return false;
  }
}

bool TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (write_callback_) {
    DCHECK(write_buffer_.get());
    net::CompletionCallback* callback = write_callback_;
    scoped_refptr<net::IOBuffer> buffer = write_buffer_;
    int buffer_len = write_buffer_len_;

    write_callback_ = NULL;
    write_buffer_ = NULL;
    write_buffer_len_ = 0;

    int result = socket_->Send(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        write_callback_ = callback;
        write_buffer_ = buffer;
        write_buffer_len_ = buffer_len;
        return true;
      }
    }
    callback->RunWithParams(Tuple1<int>(result));
    return true;
  } else {
    return false;
  }
}

}  // namespace notifier
<commit_msg>Add a "// namespace" comment after the closing curly brace of a namespace to make cpplint happy.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/notifier/communicator/ssl_socket_adapter.h"

#include "base/compiler_specific.h"
#include "chrome/browser/net/url_request_context_getter.h"
#include "chrome/browser/profile.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/client_socket_factory.h"
#include "net/url_request/url_request_context.h"

namespace notifier {

namespace {

// Convert values from <errno.h> to values from "net/base/net_errors.h"
int MapPosixError(int err) {
  // There are numerous posix error codes, but these are the ones we thus far
  // find interesting.
  switch (err) {
    case EAGAIN:
#if EWOULDBLOCK != EAGAIN
    case EWOULDBLOCK:
#endif
      return net::ERR_IO_PENDING;
    case ENETDOWN:
      return net::ERR_INTERNET_DISCONNECTED;
    case ETIMEDOUT:
      return net::ERR_TIMED_OUT;
    case ECONNRESET:
    case ENETRESET:  // Related to keep-alive
      return net::ERR_CONNECTION_RESET;
    case ECONNABORTED:
      return net::ERR_CONNECTION_ABORTED;
    case ECONNREFUSED:
      return net::ERR_CONNECTION_REFUSED;
    case EHOSTUNREACH:
    case ENETUNREACH:
      return net::ERR_ADDRESS_UNREACHABLE;
    case EADDRNOTAVAIL:
      return net::ERR_ADDRESS_INVALID;
    case 0:
      return net::OK;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return net::ERR_FAILED;
  }
}

}  // namespace

SSLSocketAdapter* SSLSocketAdapter::Create(AsyncSocket* socket) {
  return new SSLSocketAdapter(socket);
}

SSLSocketAdapter::SSLSocketAdapter(AsyncSocket* socket)
    : AsyncSocketAdapter(socket),
      ignore_bad_cert_(false),
      ALLOW_THIS_IN_INITIALIZER_LIST(
        connected_callback_(this, &SSLSocketAdapter::OnConnected)),
      ALLOW_THIS_IN_INITIALIZER_LIST(
        io_callback_(this, &SSLSocketAdapter::OnIO)),
      ssl_connected_(false),
      state_(STATE_NONE) {
  socket_ = new TransportSocket(socket, this);
}

int SSLSocketAdapter::StartSSL(const char* hostname, bool restartable) {
  DCHECK(!restartable);

  // SSLConfigService is not thread-safe, and the default values for SSLConfig
  // are correct for us, so we don't use the config service to initialize this
  // object.
  net::SSLConfig ssl_config;
  socket_->set_addr(talk_base::SocketAddress(hostname));
  ssl_socket_.reset(
      net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
          socket_, hostname, ssl_config));

  int result = ssl_socket_->Connect(&connected_callback_, NULL);

  if (result == net::ERR_IO_PENDING || result == net::OK) {
    return 0;
  } else {
    return result;
  }
}

int SSLSocketAdapter::Send(const void* buf, size_t len) {
  if (!ssl_connected_) {
    return AsyncSocketAdapter::Send(buf, len);
  } else {
    scoped_refptr<net::IOBuffer> transport_buf = new net::IOBuffer(len);
    memcpy(transport_buf->data(), buf, len);

    int result = ssl_socket_->Write(transport_buf, len, NULL);
    if (result == net::ERR_IO_PENDING) {
      SetError(EWOULDBLOCK);
    }
    transport_buf = NULL;
    return result;
  }
}

int SSLSocketAdapter::Recv(void* buf, size_t len) {
  if (!ssl_connected_) {
    return AsyncSocketAdapter::Recv(buf, len);
  }

  switch (state_) {
    case STATE_NONE: {
      transport_buf_ = new net::IOBuffer(len);
      int result = ssl_socket_->Read(transport_buf_, len, &io_callback_);
      if (result >= 0) {
        memcpy(buf, transport_buf_->data(), len);
      }

      if (result == net::ERR_IO_PENDING) {
        state_ = STATE_READ;
        SetError(EWOULDBLOCK);
      } else {
        if (result < 0) {
          SetError(result);
          LOG(INFO) << "Socket error " << result;
        }
        transport_buf_ = NULL;
      }
      return result;
    }
    case STATE_READ_COMPLETE:
      memcpy(buf, transport_buf_->data(), len);
      transport_buf_ = NULL;
      state_ = STATE_NONE;
      return data_transferred_;

    case STATE_READ:
    case STATE_WRITE:
    case STATE_WRITE_COMPLETE:
      SetError(EWOULDBLOCK);
      return -1;

    default:
      NOTREACHED();
      break;
  }
  return -1;
}

void SSLSocketAdapter::OnConnected(int result) {
  if (result == net::OK) {
    ssl_connected_ = true;
    OnConnectEvent(this);
  }
}

void SSLSocketAdapter::OnIO(int result) {
  switch (state_) {
    case STATE_READ:
      state_ = STATE_READ_COMPLETE;
      data_transferred_ = result;
      AsyncSocketAdapter::OnReadEvent(this);
      break;
    case STATE_WRITE:
      state_ = STATE_WRITE_COMPLETE;
      data_transferred_ = result;
      AsyncSocketAdapter::OnWriteEvent(this);
      break;
    case STATE_NONE:
    case STATE_READ_COMPLETE:
    case STATE_WRITE_COMPLETE:
    default:
      NOTREACHED();
      break;
  }
}

void SSLSocketAdapter::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (!socket_->OnReadEvent(socket))
    AsyncSocketAdapter::OnReadEvent(socket);
}

void SSLSocketAdapter::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (!socket_->OnWriteEvent(socket))
    AsyncSocketAdapter::OnWriteEvent(socket);
}

TransportSocket::TransportSocket(talk_base::AsyncSocket* socket,
                                 SSLSocketAdapter *ssl_adapter)
    : connect_callback_(NULL),
      read_callback_(NULL),
      write_callback_(NULL),
      read_buffer_len_(0),
      write_buffer_len_(0),
      socket_(socket) {
    socket_->SignalConnectEvent.connect(this, &TransportSocket::OnConnectEvent);
}

int TransportSocket::Connect(net::CompletionCallback* callback,
                             net::LoadLog* /* load_log */) {
  connect_callback_ = callback;
  return socket_->Connect(addr_);
}

void TransportSocket::Disconnect() {
  socket_->Close();
}

bool TransportSocket::IsConnected() const {
  return (socket_->GetState() == talk_base::Socket::CS_CONNECTED);
}

bool TransportSocket::IsConnectedAndIdle() const {
  // Not implemented.
  NOTREACHED();
  return false;
}

int TransportSocket::GetPeerName(struct sockaddr* name, socklen_t* namelen) {
  talk_base::SocketAddress address = socket_->GetRemoteAddress();
  address.ToSockAddr(reinterpret_cast<sockaddr_in *>(name));
  return 0;
}

int TransportSocket::Read(net::IOBuffer* buf, int buf_len,
                          net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!read_callback_);
  DCHECK(!read_buffer_.get());
  int result = socket_->Recv(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      read_callback_ = callback;
      read_buffer_ = buf;
      read_buffer_len_ = buf_len;
    }
  }
  return result;
}

int TransportSocket::Write(net::IOBuffer* buf, int buf_len,
                           net::CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(!write_callback_);
  DCHECK(!write_buffer_.get());
  int result = socket_->Send(buf->data(), buf_len);
  if (result < 0) {
    result = MapPosixError(socket_->GetError());
    if (result == net::ERR_IO_PENDING) {
      write_callback_ = callback;
      write_buffer_ = buf;
      write_buffer_len_ = buf_len;
    }
  }
  return result;
}

bool TransportSocket::SetReceiveBufferSize(int32 size) {
  // Not implemented.
  return false;
}

bool TransportSocket::SetSendBufferSize(int32 size) {
  // Not implemented.
  return false;
}

void TransportSocket::OnConnectEvent(talk_base::AsyncSocket * socket) {
  if (connect_callback_) {
    net::CompletionCallback *callback = connect_callback_;
    connect_callback_ = NULL;
    callback->RunWithParams(Tuple1<int>(MapPosixError(socket_->GetError())));
  }
}

bool TransportSocket::OnReadEvent(talk_base::AsyncSocket* socket) {
  if (read_callback_) {
    DCHECK(read_buffer_.get());
    net::CompletionCallback* callback = read_callback_;
    scoped_refptr<net::IOBuffer> buffer = read_buffer_;
    int buffer_len = read_buffer_len_;

    read_callback_ = NULL;
    read_buffer_ = NULL;
    read_buffer_len_ = 0;

    int result = socket_->Recv(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        read_callback_ = callback;
        read_buffer_ = buffer;
        read_buffer_len_ = buffer_len;
        return true;
      }
    }
    callback->RunWithParams(Tuple1<int>(result));
    return true;
  } else {
    return false;
  }
}

bool TransportSocket::OnWriteEvent(talk_base::AsyncSocket* socket) {
  if (write_callback_) {
    DCHECK(write_buffer_.get());
    net::CompletionCallback* callback = write_callback_;
    scoped_refptr<net::IOBuffer> buffer = write_buffer_;
    int buffer_len = write_buffer_len_;

    write_callback_ = NULL;
    write_buffer_ = NULL;
    write_buffer_len_ = 0;

    int result = socket_->Send(buffer->data(), buffer_len);
    if (result < 0) {
      result = MapPosixError(socket_->GetError());
      if (result == net::ERR_IO_PENDING) {
        write_callback_ = callback;
        write_buffer_ = buffer;
        write_buffer_len_ = buffer_len;
        return true;
      }
    }
    callback->RunWithParams(Tuple1<int>(result));
    return true;
  } else {
    return false;
  }
}

}  // namespace notifier
<|endoftext|>