<commit_before>#include "signverifymessagedialog.h"
#include "ui_signverifymessagedialog.h"

#include "addressbookpage.h"
#include "base58.h"
#include "guiutil.h"
#include "init.h"
#include "main.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "wallet.h"

#include <string>
#include <vector>

#include <QClipboard>

SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SignVerifyMessageDialog),
    model(0)
{
    ui->setupUi(this);

#if (QT_VERSION >= 0x040700)
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    ui->addressIn_SM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
    ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));

    ui->addressIn_VM->setPlaceholderText(tr("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L)"));
    ui->signatureIn_VM->setPlaceholderText(tr("Enter Bitcoin signature"));
#endif

    GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
    GUIUtil::setupAddressWidget(ui->addressIn_VM, this);

    ui->addressIn_SM->installEventFilter(this);
    ui->messageIn_SM->installEventFilter(this);
    ui->signatureOut_SM->installEventFilter(this);
    ui->addressIn_VM->installEventFilter(this);
    ui->messageIn_VM->installEventFilter(this);
    ui->signatureIn_VM->installEventFilter(this);

    ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont());
    ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont());
}

SignVerifyMessageDialog::~SignVerifyMessageDialog()
{
    delete ui;
}

void SignVerifyMessageDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void SignVerifyMessageDialog::setAddress_SM(QString address)
{
    ui->addressIn_SM->setText(address);
    ui->messageIn_SM->setFocus();
}

void SignVerifyMessageDialog::setAddress_VM(QString address)
{
    ui->addressIn_VM->setText(address);
    ui->messageIn_VM->setFocus();
}

void SignVerifyMessageDialog::showTab_SM(bool fShow)
{
    ui->tabWidget->setCurrentIndex(0);

    if (fShow)
        this->show();
}

void SignVerifyMessageDialog::showTab_VM(bool fShow)
{
    ui->tabWidget->setCurrentIndex(1);
    if (fShow)
        this->show();
}

void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
{
    if (model && model->getAddressTableModel())
    {
        AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::ReceivingTab, this);
        dlg.setModel(model->getAddressTableModel());
        if (dlg.exec())
        {
            setAddress_SM(dlg.getReturnValue());
        }
    }
}

void SignVerifyMessageDialog::on_pasteButton_SM_clicked()
{
    setAddress_SM(QApplication::clipboard()->text());
}

void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
{
    /* Clear old signature to ensure users don't get confused on error with an old signature displayed */
    ui->signatureOut_SM->clear();

    CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
    if (!addr.IsValid())
    {
        ui->addressIn_SM->setValid(false);
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }
    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
    {
        ui->addressIn_SM->setValid(false);
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    WalletModel::UnlockContext ctx(model->requestUnlock());
    if (!ctx.isValid())
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("Wallet unlock was canceled."));
        return;
    }

    CKey key;
    if (!pwalletMain->GetKey(keyID, key))
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
        return;
    }

    CDataStream ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << ui->messageIn_SM->document()->toPlainText().toStdString();

    std::vector<unsigned char> vchSig;
    if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
        return;
    }

    ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));

    ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
}

void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
{
    QApplication::clipboard()->setText(ui->signatureOut_SM->text());
}

void SignVerifyMessageDialog::on_clearButton_SM_clicked()
{
    ui->addressIn_SM->clear();
    ui->messageIn_SM->clear();
    ui->signatureOut_SM->clear();
    ui->statusLabel_SM->clear();

    ui->addressIn_SM->setFocus();
}

void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
{
    if (model && model->getAddressTableModel())
    {
        AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
        dlg.setModel(model->getAddressTableModel());
        if (dlg.exec())
        {
            setAddress_VM(dlg.getReturnValue());
        }
    }
}

void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
    CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
    if (!addr.IsValid())
    {
        ui->addressIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }
    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
    {
        ui->addressIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    bool fInvalid = false;
    std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid);

    if (fInvalid)
    {
        ui->signatureIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again."));
        return;
    }

    CDataStream ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << ui->messageIn_VM->document()->toPlainText().toStdString();

    CKey key;
    if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
    {
        ui->signatureIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again."));
        return;
    }

    if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr))
    {
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
        return;
    }

    ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>"));
}

void SignVerifyMessageDialog::on_clearButton_VM_clicked()
{
    ui->addressIn_VM->clear();
    ui->signatureIn_VM->clear();
    ui->messageIn_VM->clear();
    ui->statusLabel_VM->clear();

    ui->addressIn_VM->setFocus();
}

bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn)
    {
        if (ui->tabWidget->currentIndex() == 0)
        {
            /* Clear status message on focus change */
            ui->statusLabel_SM->clear();

            /* Select generated signature */
            if (object == ui->signatureOut_SM)
            {
                ui->signatureOut_SM->selectAll();
                return true;
            }
        }
        else if (ui->tabWidget->currentIndex() == 1)
        {
            /* Clear status message on focus change */
            ui->statusLabel_VM->clear();
        }
    }
    return QDialog::eventFilter(object, event);
}
<commit_msg>Update signverifymessagedialog.cpp<commit_after>#include "signverifymessagedialog.h"
#include "ui_signverifymessagedialog.h"

#include "addressbookpage.h"
#include "base58.h"
#include "guiutil.h"
#include "init.h"
#include "main.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "wallet.h"

#include <string>
#include <vector>

#include <QClipboard>

SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SignVerifyMessageDialog),
    model(0)
{
    ui->setupUi(this);

#if (QT_VERSION >= 0x040700)
    /* Do not move this to the XML file, Qt before 4.7 will choke on it */
    ui->addressIn_SM->setPlaceholderText(tr("Enter a Globalcoin address (e.g. 7R5GXEFk2uGoT8bba8NCpGhY3WbTFA8Ws1)"));
    ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));

    ui->addressIn_VM->setPlaceholderText(tr("Enter a Globalcoin address (e.g. 7R5GXEFk2uGoT8bba8NCpGhY3WbTFA8Ws1)"));
    ui->signatureIn_VM->setPlaceholderText(tr("Enter Globalcoin signature"));
#endif

    GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
    GUIUtil::setupAddressWidget(ui->addressIn_VM, this);

    ui->addressIn_SM->installEventFilter(this);
    ui->messageIn_SM->installEventFilter(this);
    ui->signatureOut_SM->installEventFilter(this);
    ui->addressIn_VM->installEventFilter(this);
    ui->messageIn_VM->installEventFilter(this);
    ui->signatureIn_VM->installEventFilter(this);

    ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont());
    ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont());
}

SignVerifyMessageDialog::~SignVerifyMessageDialog()
{
    delete ui;
}

void SignVerifyMessageDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void SignVerifyMessageDialog::setAddress_SM(QString address)
{
    ui->addressIn_SM->setText(address);
    ui->messageIn_SM->setFocus();
}

void SignVerifyMessageDialog::setAddress_VM(QString address)
{
    ui->addressIn_VM->setText(address);
    ui->messageIn_VM->setFocus();
}

void SignVerifyMessageDialog::showTab_SM(bool fShow)
{
    ui->tabWidget->setCurrentIndex(0);

    if (fShow)
        this->show();
}

void SignVerifyMessageDialog::showTab_VM(bool fShow)
{
    ui->tabWidget->setCurrentIndex(1);
    if (fShow)
        this->show();
}

void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
{
    if (model && model->getAddressTableModel())
    {
        AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::ReceivingTab, this);
        dlg.setModel(model->getAddressTableModel());
        if (dlg.exec())
        {
            setAddress_SM(dlg.getReturnValue());
        }
    }
}

void SignVerifyMessageDialog::on_pasteButton_SM_clicked()
{
    setAddress_SM(QApplication::clipboard()->text());
}

void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
{
    /* Clear old signature to ensure users don't get confused on error with an old signature displayed */
    ui->signatureOut_SM->clear();

    CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
    if (!addr.IsValid())
    {
        ui->addressIn_SM->setValid(false);
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }
    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
    {
        ui->addressIn_SM->setValid(false);
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    WalletModel::UnlockContext ctx(model->requestUnlock());
    if (!ctx.isValid())
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("Wallet unlock was canceled."));
        return;
    }

    CKey key;
    if (!pwalletMain->GetKey(keyID, key))
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
        return;
    }

    CDataStream ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << ui->messageIn_SM->document()->toPlainText().toStdString();

    std::vector<unsigned char> vchSig;
    if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
    {
        ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
        return;
    }

    ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));

    ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size())));
}

void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
{
    QApplication::clipboard()->setText(ui->signatureOut_SM->text());
}

void SignVerifyMessageDialog::on_clearButton_SM_clicked()
{
    ui->addressIn_SM->clear();
    ui->messageIn_SM->clear();
    ui->signatureOut_SM->clear();
    ui->statusLabel_SM->clear();

    ui->addressIn_SM->setFocus();
}

void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
{
    if (model && model->getAddressTableModel())
    {
        AddressBookPage dlg(AddressBookPage::ForSending, AddressBookPage::SendingTab, this);
        dlg.setModel(model->getAddressTableModel());
        if (dlg.exec())
        {
            setAddress_VM(dlg.getReturnValue());
        }
    }
}

void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
    CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
    if (!addr.IsValid())
    {
        ui->addressIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }
    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
    {
        ui->addressIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
        return;
    }

    bool fInvalid = false;
    std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid);

    if (fInvalid)
    {
        ui->signatureIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again."));
        return;
    }

    CDataStream ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << ui->messageIn_VM->document()->toPlainText().toStdString();

    CKey key;
    if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
    {
        ui->signatureIn_VM->setValid(false);
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again."));
        return;
    }

    if (!(CBitcoinAddress(key.GetPubKey().GetID()) == addr))
    {
        ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
        return;
    }

    ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }");
    ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>"));
}

void SignVerifyMessageDialog::on_clearButton_VM_clicked()
{
    ui->addressIn_VM->clear();
    ui->signatureIn_VM->clear();
    ui->messageIn_VM->clear();
    ui->statusLabel_VM->clear();

    ui->addressIn_VM->setFocus();
}

bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn)
    {
        if (ui->tabWidget->currentIndex() == 0)
        {
            /* Clear status message on focus change */
            ui->statusLabel_SM->clear();

            /* Select generated signature */
            if (object == ui->signatureOut_SM)
            {
                ui->signatureOut_SM->selectAll();
                return true;
            }
        }
        else if (ui->tabWidget->currentIndex() == 1)
        {
            /* Clear status message on focus change */
            ui->statusLabel_VM->clear();
        }
    }
    return QDialog::eventFilter(object, event);
}
<|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/thumbnail_store.h"

#include <string.h>
#include <algorithm>

#include "app/gfx/codec/jpeg_codec.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/md5.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_service.h"
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkBitmap.h"

ThumbnailStore::ThumbnailStore()
    : cache_(NULL),
      hs_(NULL),
      url_blacklist_(NULL),
      disk_data_loaded_(false) {
}

ThumbnailStore::~ThumbnailStore() {
  // Ensure that shutdown was called.
  DCHECK(hs_ == NULL);
}

void ThumbnailStore::Init(const FilePath& db_name, Profile* profile) {
  // Load thumbnails already in the database.
  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::InitializeFromDB,
                        db_name, MessageLoop::current()));

  // Take ownership of a reference to the HistoryService.
  hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS);

  // Store a pointer to a persistent table of blacklisted URLs.
  url_blacklist_ = profile->GetPrefs()->
    GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist);

  // Get the list of most visited URLs and redirect information from the
  // HistoryService.
  most_visited_urls_.reset(new MostVisitedMap);
  timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this,
      &ThumbnailStore::UpdateURLData);
  UpdateURLData();

  // Register to get notified when the history is cleared.
  registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
                 Source<Profile>(profile));
}

bool ThumbnailStore::SetPageThumbnail(const GURL& url,
                                      const SkBitmap& thumbnail,
                                      const ThumbnailScore& score,
                                      bool fetch_redirects) {
  if (!cache_.get())
    return false;

  if (!ShouldStoreThumbnailForURL(url) ||
      (cache_->find(url) != cache_->end() &&
      !ShouldReplaceThumbnailWith((*cache_)[url].score_, score)))
    return true;

  base::TimeTicks encode_start = base::TimeTicks::Now();

  // Encode the SkBitmap to jpeg.
  scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes;
  SkAutoLockPixels thumbnail_lock(thumbnail);
  bool encoded = gfx::JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)),
      gfx::JPEGCodec::FORMAT_BGRA, thumbnail.width(),
      thumbnail.height(),
      static_cast<int>(thumbnail.rowBytes()), 90,
      &jpeg_data->data);

  base::TimeDelta delta = base::TimeTicks::Now() - encode_start;
  HISTOGRAM_TIMES("Thumbnail.Encode", delta);

  if (!encoded)
    return false;

  // Update the cache_ with the new thumbnail.
  (*cache_)[url] = CacheEntry(jpeg_data, score, true);

  // Get redirects for this URL.
  if (fetch_redirects) {
    hs_->QueryRedirectsTo(url, &consumer_,
        NewCallback(this, &ThumbnailStore::OnRedirectsForURLAvailable));
  }

  return true;
}

bool ThumbnailStore::GetPageThumbnail(
    const GURL& url,
    RefCountedBytes** data) {
  if (!cache_.get() || IsURLBlacklisted(url))
    return false;

  // Look up the |url| in the redirect list to find the final destination
  // which is the key into the |cache_|.
  history::RedirectMap::iterator it = redirect_urls_->find(url);
  if (it != redirect_urls_->end()) {
    // Return the first available thumbnail starting at the end of the
    // redirect list.
    history::RedirectList::reverse_iterator rit;
    for (rit = it->second->data.rbegin();
        rit != it->second->data.rend(); ++rit) {
      if (cache_->find(*rit) != cache_->end()) {
        *data = (*cache_)[*rit].data_.get();
        (*data)->AddRef();
        return true;
      }
    }
  }

  // TODO(meelapshah) bug 14643: check past redirect lists

  if (cache_->find(url) == cache_->end())
    return false;

  *data = (*cache_)[url].data_.get();
  (*data)->AddRef();
  return true;
}

void ThumbnailStore::Shutdown() {
  // We must release our reference to the HistoryService here to prevent
  // shutdown issues. Please refer to the comment in HistoryService::Cleanup
  // for details.
  hs_ = NULL;

  // De-register for notifications.
  registrar_.RemoveAll();

  // Stop the timer to ensure that UpdateURLData is not called during shutdown.
  timer_.Stop();

  // Write the cache to disk.  This will schedule the disk operations to be run
  // on the file_thread.  Note that Join() does not need to be called with the
  // file_thread because when the disk operation is scheduled, it will hold a
  // reference to |this| keeping this object alive.
  CleanCacheData();
}

void ThumbnailStore::OnRedirectsForURLAvailable(
    HistoryService::Handle handle,
    GURL url,
    bool success,
    history::RedirectList* redirects) {
  if (!success)
    return;

  DCHECK(redirect_urls_.get());

  // If A -> B -> C is a redirect chain, then this function would be called
  // with url=C and redirects = {B, A}. This is entered into the RedirectMap as
  // A => {B -> C}.
  if (redirects->empty()) {
    (*redirect_urls_)[url] = new RefCountedVector<GURL>;
  } else {
    const GURL start_url = redirects->back();
    std::reverse(redirects->begin(), redirects->end() - 1);
    *(redirects->end() - 1) = url;
    (*redirect_urls_)[start_url] = new RefCountedVector<GURL>(*redirects);
  }
}

history::RedirectMap::iterator ThumbnailStore::GetRedirectIteratorForURL(
    const GURL& url) const {
  for (history::RedirectMap::iterator it = redirect_urls_->begin();
      it != redirect_urls_->end(); ++it) {
    if (it->first == url ||
        (!it->second->data.empty() && it->second->data.back() == url))
      return it;
  }
  return redirect_urls_->end();
}

void ThumbnailStore::Observe(NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  if (type.value != NotificationType::HISTORY_URLS_DELETED) {
    NOTREACHED();
    return;
  }

  Details<history::URLsDeletedDetails> url_details(details);
  // If all history was cleared, clear all of our data and reset the update
  // timer.
  if (url_details->all_history) {
    most_visited_urls_->clear();
    redirect_urls_->clear();
    cache_->clear();
    timer_.Reset();
  }
}

void ThumbnailStore::NotifyThumbnailStoreReady() {
  NotificationService::current()->Notify(
      NotificationType::THUMBNAIL_STORE_READY,
      Source<ThumbnailStore>(this),
      NotificationService::NoDetails());
}

void ThumbnailStore::UpdateURLData() {
  DCHECK(url_blacklist_);

  int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize();
  hs_->QueryTopURLsAndRedirects(result_count, &consumer_,
      NewCallback(this, &ThumbnailStore::OnURLDataAvailable));
}

void ThumbnailStore::OnURLDataAvailable(HistoryService::Handle handle,
                                        bool success,
                                        std::vector<GURL>* urls,
                                        history::RedirectMap* redirects) {
  if (!success)
    return;

  DCHECK(urls);
  DCHECK(redirects);

  // Each element of |urls| is the start of a redirect chain. When thumbnails
  // are stored from TabContents, the tails of the redirect chains are
  // associated with the image. Since SetPageThumbnail is called frequently, we
  // look up the tail end of each element in |urls| and insert that into the
  // MostVisitedMap. This way SetPageThumbnail can more quickly check if a
  // given url is in the most visited list.
  most_visited_urls_->clear();
  for (size_t i = 0; i < urls->size(); ++i) {
    history::RedirectMap::iterator it = redirects->find(urls->at(i));
    if (it->second->data.empty())
      (*most_visited_urls_)[urls->at(i)] = GURL();
    else
      (*most_visited_urls_)[it->second->data.back()] = urls->at(i);
  }
  redirect_urls_.reset(new history::RedirectMap(*redirects));

  if (IsReady())
    NotifyThumbnailStoreReady();

  CleanCacheData();
}

void ThumbnailStore::CleanCacheData() {
  if (!cache_.get())
    return;

  scoped_refptr<RefCountedVector<GURL> > urls_to_delete =
      new RefCountedVector<GURL>;
  Cache* data_to_save = new Cache;  // CommitCacheToDB will delete this

  // Iterate the cache, storing urls to be deleted and dirty cache entries to
  // be written to disk.
  for (Cache::iterator cache_it = cache_->begin();
       cache_it != cache_->end();) {
    history::RedirectMap::iterator redirect_it =
        GetRedirectIteratorForURL(cache_it->first);
    const GURL* url = redirect_it == redirect_urls_->end() ?
                          NULL : &redirect_it->first;

    // If this URL is blacklisted or not in the most visited list, mark it for
    // deletion. Otherwise, if the cache entry is dirty, mark it to be written
    // to disk.
    if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) {
      urls_to_delete->data.push_back(cache_it->first);
      cache_->erase(cache_it++);
    } else {
      if (cache_it->second.dirty_) {
        data_to_save->insert(*cache_it);
        cache_it->second.dirty_ = false;
      }
      ++cache_it;
    }
  }

  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::CommitCacheToDB,
                        urls_to_delete, data_to_save));
}

void ThumbnailStore::CommitCacheToDB(
    scoped_refptr<RefCountedVector<GURL> > urls_to_delete,
    Cache* data) {
  scoped_ptr<Cache> data_to_save(data);
  if (!db_.is_open())
    return;

  base::TimeTicks db_start = base::TimeTicks::Now();

  sql::Transaction transaction(&db_);
  if (!transaction.Begin())
    return;

  // Delete old thumbnails.
  if (urls_to_delete.get()) {
    for (std::vector<GURL>::iterator it = urls_to_delete->data.begin();
        it != urls_to_delete->data.end(); ++it) {
      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
          "DELETE FROM thumbnails WHERE url=?"));
      if (!statement)
        return;
      statement.BindString(0, it->spec());
      if (!statement.Run())
        NOTREACHED();
    }
  }

  // Update cached thumbnails.
  if (data_to_save.get()) {
    for (Cache::iterator it = data_to_save->begin();
         it != data_to_save->end(); ++it) {
      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
          "INSERT OR REPLACE INTO thumbnails "
          "(url, boring_score, good_clipping, "
          "at_top, time_taken, data) "
          "VALUES (?,?,?,?,?,?)"));
      statement.BindString(0, it->first.spec());
      statement.BindDouble(1, it->second.score_.boring_score);
      statement.BindBool(2, it->second.score_.good_clipping);
      statement.BindBool(3, it->second.score_.at_top);
      statement.BindInt64(4,
          it->second.score_.time_at_snapshot.ToInternalValue());
      statement.BindBlob(5, &it->second.data_->data[0],
                          static_cast<int>(it->second.data_->data.size()));
      if (!statement.Run())
        DLOG(WARNING) << "Unable to insert thumbnail for URL";
    }
  }

  transaction.Commit();

  base::TimeDelta delta = base::TimeTicks::Now() - db_start;
  HISTOGRAM_TIMES("ThumbnailStore.WriteDBToDisk", delta);
}

void ThumbnailStore::InitializeFromDB(const FilePath& db_name,
                                      MessageLoop* cb_loop) {
  db_.set_page_size(4096);
  db_.set_cache_size(64);
  db_.set_exclusive_locking();
  if (!db_.Open(db_name))
    return;

  if (!db_.DoesTableExist("thumbnails")) {
    if (!db_.Execute("CREATE TABLE thumbnails ("
          "url LONGVARCHAR PRIMARY KEY,"
          "boring_score DOUBLE DEFAULT 1.0,"
          "good_clipping INTEGER DEFAULT 0,"
          "at_top INTEGER DEFAULT 0,"
          "time_taken INTEGER DEFAULT 0,"
          "data BLOB)"))
      return;
  }

  if (cb_loop)
    GetAllThumbnailsFromDisk(cb_loop);
}

void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) {
  Cache* cache = new Cache;

  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT * FROM thumbnails"));
  if (!statement)
    return;

  while (statement.Step()) {
    // The URL
    GURL url(statement.ColumnString(0));

    // The score.
    ThumbnailScore score(statement.ColumnDouble(1),      // Boring score
                         statement.ColumnBool(2),        // Good clipping
                         statement.ColumnBool(3),        // At top
                         base::Time::FromInternalValue(
                            statement.ColumnInt64(4)));  // Time taken

    // The image.
    scoped_refptr<RefCountedBytes> data = new RefCountedBytes;
    statement.ColumnBlobAsVector(5, &data->data);
    (*cache)[url] = CacheEntry(data, score, false);
  }

  cb_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache));
}

void ThumbnailStore::OnDiskDataAvailable(Cache* cache) {
  if (cache)
    cache_.reset(cache);

  disk_data_loaded_ = true;
  if (IsReady())
    NotifyThumbnailStoreReady();
}

bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const {
  if (!cache_.get())
    return false;

  if (IsURLBlacklisted(url) || cache_->size() >= kMaxCacheSize)
    return false;

  return IsPopular(url);
}

bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const {
  if (url_blacklist_)
    return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec()));
  return false;
}

std::wstring ThumbnailStore::GetDictionaryKeyForURL(
    const std::string& url) const {
  return ASCIIToWide(MD5String(url));
}

bool ThumbnailStore::IsPopular(const GURL& url) const {
  return most_visited_urls_->size() < kMaxCacheSize ||
         most_visited_urls_->find(url) != most_visited_urls_->end();
}
<commit_msg>Coverity: Allocate |cache| after we have a logic path where we can return and leak.<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/thumbnail_store.h"

#include <string.h>
#include <algorithm>

#include "app/gfx/codec/jpeg_codec.h"
#include "app/sql/statement.h"
#include "app/sql/transaction.h"
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/md5.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profile.h"
#include "chrome/common/pref_service.h"
#include "googleurl/src/gurl.h"
#include "third_party/skia/include/core/SkBitmap.h"

ThumbnailStore::ThumbnailStore()
    : cache_(NULL),
      hs_(NULL),
      url_blacklist_(NULL),
      disk_data_loaded_(false) {
}

ThumbnailStore::~ThumbnailStore() {
  // Ensure that shutdown was called.
  DCHECK(hs_ == NULL);
}

void ThumbnailStore::Init(const FilePath& db_name, Profile* profile) {
  // Load thumbnails already in the database.
  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::InitializeFromDB,
                        db_name, MessageLoop::current()));

  // Take ownership of a reference to the HistoryService.
  hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS);

  // Store a pointer to a persistent table of blacklisted URLs.
  url_blacklist_ = profile->GetPrefs()->
    GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist);

  // Get the list of most visited URLs and redirect information from the
  // HistoryService.
  most_visited_urls_.reset(new MostVisitedMap);
  timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this,
      &ThumbnailStore::UpdateURLData);
  UpdateURLData();

  // Register to get notified when the history is cleared.
  registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
                 Source<Profile>(profile));
}

bool ThumbnailStore::SetPageThumbnail(const GURL& url,
                                      const SkBitmap& thumbnail,
                                      const ThumbnailScore& score,
                                      bool fetch_redirects) {
  if (!cache_.get())
    return false;

  if (!ShouldStoreThumbnailForURL(url) ||
      (cache_->find(url) != cache_->end() &&
      !ShouldReplaceThumbnailWith((*cache_)[url].score_, score)))
    return true;

  base::TimeTicks encode_start = base::TimeTicks::Now();

  // Encode the SkBitmap to jpeg.
  scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes;
  SkAutoLockPixels thumbnail_lock(thumbnail);
  bool encoded = gfx::JPEGCodec::Encode(
      reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)),
      gfx::JPEGCodec::FORMAT_BGRA, thumbnail.width(),
      thumbnail.height(),
      static_cast<int>(thumbnail.rowBytes()), 90,
      &jpeg_data->data);

  base::TimeDelta delta = base::TimeTicks::Now() - encode_start;
  HISTOGRAM_TIMES("Thumbnail.Encode", delta);

  if (!encoded)
    return false;

  // Update the cache_ with the new thumbnail.
  (*cache_)[url] = CacheEntry(jpeg_data, score, true);

  // Get redirects for this URL.
  if (fetch_redirects) {
    hs_->QueryRedirectsTo(url, &consumer_,
        NewCallback(this, &ThumbnailStore::OnRedirectsForURLAvailable));
  }

  return true;
}

bool ThumbnailStore::GetPageThumbnail(
    const GURL& url,
    RefCountedBytes** data) {
  if (!cache_.get() || IsURLBlacklisted(url))
    return false;

  // Look up the |url| in the redirect list to find the final destination
  // which is the key into the |cache_|.
  history::RedirectMap::iterator it = redirect_urls_->find(url);
  if (it != redirect_urls_->end()) {
    // Return the first available thumbnail starting at the end of the
    // redirect list.
    history::RedirectList::reverse_iterator rit;
    for (rit = it->second->data.rbegin();
        rit != it->second->data.rend(); ++rit) {
      if (cache_->find(*rit) != cache_->end()) {
        *data = (*cache_)[*rit].data_.get();
        (*data)->AddRef();
        return true;
      }
    }
  }

  // TODO(meelapshah) bug 14643: check past redirect lists

  if (cache_->find(url) == cache_->end())
    return false;

  *data = (*cache_)[url].data_.get();
  (*data)->AddRef();
  return true;
}

void ThumbnailStore::Shutdown() {
  // We must release our reference to the HistoryService here to prevent
  // shutdown issues. Please refer to the comment in HistoryService::Cleanup
  // for details.
  hs_ = NULL;

  // De-register for notifications.
  registrar_.RemoveAll();

  // Stop the timer to ensure that UpdateURLData is not called during shutdown.
  timer_.Stop();

  // Write the cache to disk.  This will schedule the disk operations to be run
  // on the file_thread.  Note that Join() does not need to be called with the
  // file_thread because when the disk operation is scheduled, it will hold a
  // reference to |this| keeping this object alive.
  CleanCacheData();
}

void ThumbnailStore::OnRedirectsForURLAvailable(
    HistoryService::Handle handle,
    GURL url,
    bool success,
    history::RedirectList* redirects) {
  if (!success)
    return;

  DCHECK(redirect_urls_.get());

  // If A -> B -> C is a redirect chain, then this function would be called
  // with url=C and redirects = {B, A}. This is entered into the RedirectMap as
  // A => {B -> C}.
  if (redirects->empty()) {
    (*redirect_urls_)[url] = new RefCountedVector<GURL>;
  } else {
    const GURL start_url = redirects->back();
    std::reverse(redirects->begin(), redirects->end() - 1);
    *(redirects->end() - 1) = url;
    (*redirect_urls_)[start_url] = new RefCountedVector<GURL>(*redirects);
  }
}

history::RedirectMap::iterator ThumbnailStore::GetRedirectIteratorForURL(
    const GURL& url) const {
  for (history::RedirectMap::iterator it = redirect_urls_->begin();
      it != redirect_urls_->end(); ++it) {
    if (it->first == url ||
        (!it->second->data.empty() && it->second->data.back() == url))
      return it;
  }
  return redirect_urls_->end();
}

void ThumbnailStore::Observe(NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  if (type.value != NotificationType::HISTORY_URLS_DELETED) {
    NOTREACHED();
    return;
  }

  Details<history::URLsDeletedDetails> url_details(details);
  // If all history was cleared, clear all of our data and reset the update
  // timer.
  if (url_details->all_history) {
    most_visited_urls_->clear();
    redirect_urls_->clear();
    cache_->clear();
    timer_.Reset();
  }
}

void ThumbnailStore::NotifyThumbnailStoreReady() {
  NotificationService::current()->Notify(
      NotificationType::THUMBNAIL_STORE_READY,
      Source<ThumbnailStore>(this),
      NotificationService::NoDetails());
}

void ThumbnailStore::UpdateURLData() {
  DCHECK(url_blacklist_);

  int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize();
  hs_->QueryTopURLsAndRedirects(result_count, &consumer_,
      NewCallback(this, &ThumbnailStore::OnURLDataAvailable));
}

void ThumbnailStore::OnURLDataAvailable(HistoryService::Handle handle,
                                        bool success,
                                        std::vector<GURL>* urls,
                                        history::RedirectMap* redirects) {
  if (!success)
    return;

  DCHECK(urls);
  DCHECK(redirects);

  // Each element of |urls| is the start of a redirect chain. When thumbnails
  // are stored from TabContents, the tails of the redirect chains are
  // associated with the image. Since SetPageThumbnail is called frequently, we
  // look up the tail end of each element in |urls| and insert that into the
  // MostVisitedMap. This way SetPageThumbnail can more quickly check if a
  // given url is in the most visited list.
  most_visited_urls_->clear();
  for (size_t i = 0; i < urls->size(); ++i) {
    history::RedirectMap::iterator it = redirects->find(urls->at(i));
    if (it->second->data.empty())
      (*most_visited_urls_)[urls->at(i)] = GURL();
    else
      (*most_visited_urls_)[it->second->data.back()] = urls->at(i);
  }
  redirect_urls_.reset(new history::RedirectMap(*redirects));

  if (IsReady())
    NotifyThumbnailStoreReady();

  CleanCacheData();
}

void ThumbnailStore::CleanCacheData() {
  if (!cache_.get())
    return;

  scoped_refptr<RefCountedVector<GURL> > urls_to_delete =
      new RefCountedVector<GURL>;
  Cache* data_to_save = new Cache;  // CommitCacheToDB will delete this

  // Iterate the cache, storing urls to be deleted and dirty cache entries to
  // be written to disk.
  for (Cache::iterator cache_it = cache_->begin();
       cache_it != cache_->end();) {
    history::RedirectMap::iterator redirect_it =
        GetRedirectIteratorForURL(cache_it->first);
    const GURL* url = redirect_it == redirect_urls_->end() ?
                          NULL : &redirect_it->first;

    // If this URL is blacklisted or not in the most visited list, mark it for
    // deletion. Otherwise, if the cache entry is dirty, mark it to be written
    // to disk.
    if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) {
      urls_to_delete->data.push_back(cache_it->first);
      cache_->erase(cache_it++);
    } else {
      if (cache_it->second.dirty_) {
        data_to_save->insert(*cache_it);
        cache_it->second.dirty_ = false;
      }
      ++cache_it;
    }
  }

  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::CommitCacheToDB,
                        urls_to_delete, data_to_save));
}

void ThumbnailStore::CommitCacheToDB(
    scoped_refptr<RefCountedVector<GURL> > urls_to_delete,
    Cache* data) {
  scoped_ptr<Cache> data_to_save(data);
  if (!db_.is_open())
    return;

  base::TimeTicks db_start = base::TimeTicks::Now();

  sql::Transaction transaction(&db_);
  if (!transaction.Begin())
    return;

  // Delete old thumbnails.
  if (urls_to_delete.get()) {
    for (std::vector<GURL>::iterator it = urls_to_delete->data.begin();
        it != urls_to_delete->data.end(); ++it) {
      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
          "DELETE FROM thumbnails WHERE url=?"));
      if (!statement)
        return;
      statement.BindString(0, it->spec());
      if (!statement.Run())
        NOTREACHED();
    }
  }

  // Update cached thumbnails.
  if (data_to_save.get()) {
    for (Cache::iterator it = data_to_save->begin();
         it != data_to_save->end(); ++it) {
      sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
          "INSERT OR REPLACE INTO thumbnails "
          "(url, boring_score, good_clipping, "
          "at_top, time_taken, data) "
          "VALUES (?,?,?,?,?,?)"));
      statement.BindString(0, it->first.spec());
      statement.BindDouble(1, it->second.score_.boring_score);
      statement.BindBool(2, it->second.score_.good_clipping);
      statement.BindBool(3, it->second.score_.at_top);
      statement.BindInt64(4,
          it->second.score_.time_at_snapshot.ToInternalValue());
      statement.BindBlob(5, &it->second.data_->data[0],
                          static_cast<int>(it->second.data_->data.size()));
      if (!statement.Run())
        DLOG(WARNING) << "Unable to insert thumbnail for URL";
    }
  }

  transaction.Commit();

  base::TimeDelta delta = base::TimeTicks::Now() - db_start;
  HISTOGRAM_TIMES("ThumbnailStore.WriteDBToDisk", delta);
}

void ThumbnailStore::InitializeFromDB(const FilePath& db_name,
                                      MessageLoop* cb_loop) {
  db_.set_page_size(4096);
  db_.set_cache_size(64);
  db_.set_exclusive_locking();
  if (!db_.Open(db_name))
    return;

  if (!db_.DoesTableExist("thumbnails")) {
    if (!db_.Execute("CREATE TABLE thumbnails ("
          "url LONGVARCHAR PRIMARY KEY,"
          "boring_score DOUBLE DEFAULT 1.0,"
          "good_clipping INTEGER DEFAULT 0,"
          "at_top INTEGER DEFAULT 0,"
          "time_taken INTEGER DEFAULT 0,"
          "data BLOB)"))
      return;
  }

  if (cb_loop)
    GetAllThumbnailsFromDisk(cb_loop);
}

void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) {
  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
      "SELECT * FROM thumbnails"));
  if (!statement)
    return;

  Cache* cache = new Cache;
  while (statement.Step()) {
    // The URL
    GURL url(statement.ColumnString(0));

    // The score.
    ThumbnailScore score(statement.ColumnDouble(1),      // Boring score
                         statement.ColumnBool(2),        // Good clipping
                         statement.ColumnBool(3),        // At top
                         base::Time::FromInternalValue(
                            statement.ColumnInt64(4)));  // Time taken

    // The image.
    scoped_refptr<RefCountedBytes> data = new RefCountedBytes;
    statement.ColumnBlobAsVector(5, &data->data);
    (*cache)[url] = CacheEntry(data, score, false);
  }

  cb_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache));
}

void ThumbnailStore::OnDiskDataAvailable(Cache* cache) {
  if (cache)
    cache_.reset(cache);

  disk_data_loaded_ = true;
  if (IsReady())
    NotifyThumbnailStoreReady();
}

bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const {
  if (!cache_.get())
    return false;

  if (IsURLBlacklisted(url) || cache_->size() >= kMaxCacheSize)
    return false;

  return IsPopular(url);
}

bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const {
  if (url_blacklist_)
    return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec()));
  return false;
}

std::wstring ThumbnailStore::GetDictionaryKeyForURL(
    const std::string& url) const {
  return ASCIIToWide(MD5String(url));
}

bool ThumbnailStore::IsPopular(const GURL& url) const {
  return most_visited_urls_->size() < kMaxCacheSize ||
         most_visited_urls_->find(url) != most_visited_urls_->end();
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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/views/single_split_view.h"

#include "base/gfx/skia_utils.h"
#include "chrome/common/gfx/chrome_canvas.h"

namespace views {

// Size of the divider in pixels.
static const int kDividerSize = 6;

SingleSplitView::SingleSplitView(View* leading,
                                 View* trailing) : divider_x_(-1) {
  AddChildView(leading);
  AddChildView(trailing);
}

void SingleSplitView::PaintBackground(ChromeCanvas* canvas) {
  canvas->drawColor(gfx::COLORREFToSkColor(GetSysColor(COLOR_3DFACE)),
                    SkPorterDuff::kSrc_Mode);
}

void SingleSplitView::Layout() {
  if (GetChildViewCount() != 2)
    return;

  View* leading = GetChildViewAt(0);
  View* trailing = GetChildViewAt(1);
  if (divider_x_ < 0)
    divider_x_ = (width() - kDividerSize) / 2;
  else
    divider_x_ = std::min(divider_x_, width() - kDividerSize);
  leading->SetBounds(0, 0, divider_x_, height());
  trailing->SetBounds(divider_x_ + kDividerSize, 0,
                      width() - divider_x_ - kDividerSize, height());

  SchedulePaint();

  // Invoke super's implementation so that the children are layed out.
  View::Layout();
}

gfx::Size SingleSplitView::GetPreferredSize() {
  int width = 0;
  int height = 0;
  for (int i = 0; i < 2 && i < GetChildViewCount(); ++i) {
    View* view = GetChildViewAt(i);
    gfx::Size pref = view->GetPreferredSize();
    width += pref.width();
    height = std::max(height, pref.height());
  }
  width += kDividerSize;
  return gfx::Size(width, height);
}

HCURSOR SingleSplitView::GetCursorForPoint(Event::EventType event_type,
                                           int x,
                                           int y) {
  if (IsPointInDivider(x)) {
    static HCURSOR resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
    return resize_cursor;
  }
  return NULL;
}

bool SingleSplitView::OnMousePressed(const MouseEvent& event) {
  if (!IsPointInDivider(event.x()))
    return false;
  drag_info_.initial_mouse_x = event.x();
  drag_info_.initial_divider_x = divider_x_;
  return true;
}

bool SingleSplitView::OnMouseDragged(const MouseEvent& event) {
  if (GetChildViewCount() < 2)
    return false;

  int delta_x = event.x() - drag_info_.initial_mouse_x;
  if (UILayoutIsRightToLeft())
    delta_x *= -1;
  // Honor the minimum size when resizing.
  int new_width = std::max(GetChildViewAt(0)->GetMinimumSize().width(),
                           drag_info_.initial_divider_x + delta_x);

  // And don't let the view get bigger than our width.
  new_width = std::min(width() - kDividerSize, new_width);

  if (new_width != divider_x_) {
    set_divider_x(new_width);
    Layout();
  }
  return true;
}

void SingleSplitView::OnMouseReleased(const MouseEvent& event, bool canceled) {
  if (GetChildViewCount() < 2)
    return;

  if (canceled && drag_info_.initial_divider_x != divider_x_) {
    set_divider_x(drag_info_.initial_divider_x);
    Layout();
  }
}

bool SingleSplitView::IsPointInDivider(int x) {
  if (GetChildViewCount() < 2)
    return false;

  View* leading = GetChildViewAt(0);
  int divider_relative_x =
      x - MirroredXCoordinateInsideView(leading->width());
  return (divider_relative_x >= 0 && divider_relative_x < kDividerSize);
}

}  // namespace views
<commit_msg>Fixes resizing of single split view for RTL case.<commit_after>// Copyright (c) 2006-2008 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/views/single_split_view.h"

#include "base/gfx/skia_utils.h"
#include "chrome/common/gfx/chrome_canvas.h"

namespace views {

// Size of the divider in pixels.
static const int kDividerSize = 6;

SingleSplitView::SingleSplitView(View* leading,
                                 View* trailing) : divider_x_(-1) {
  AddChildView(leading);
  AddChildView(trailing);
}

void SingleSplitView::PaintBackground(ChromeCanvas* canvas) {
  canvas->drawColor(gfx::COLORREFToSkColor(GetSysColor(COLOR_3DFACE)),
                    SkPorterDuff::kSrc_Mode);
}

void SingleSplitView::Layout() {
  if (GetChildViewCount() != 2)
    return;

  View* leading = GetChildViewAt(0);
  View* trailing = GetChildViewAt(1);
  if (divider_x_ < 0)
    divider_x_ = (width() - kDividerSize) / 2;
  else
    divider_x_ = std::min(divider_x_, width() - kDividerSize);
  leading->SetBounds(0, 0, divider_x_, height());
  trailing->SetBounds(divider_x_ + kDividerSize, 0,
                      width() - divider_x_ - kDividerSize, height());

  SchedulePaint();

  // Invoke super's implementation so that the children are layed out.
  View::Layout();
}

gfx::Size SingleSplitView::GetPreferredSize() {
  int width = 0;
  int height = 0;
  for (int i = 0; i < 2 && i < GetChildViewCount(); ++i) {
    View* view = GetChildViewAt(i);
    gfx::Size pref = view->GetPreferredSize();
    width += pref.width();
    height = std::max(height, pref.height());
  }
  width += kDividerSize;
  return gfx::Size(width, height);
}

HCURSOR SingleSplitView::GetCursorForPoint(Event::EventType event_type,
                                           int x,
                                           int y) {
  if (IsPointInDivider(x)) {
    static HCURSOR resize_cursor = LoadCursor(NULL, IDC_SIZEWE);
    return resize_cursor;
  }
  return NULL;
}

bool SingleSplitView::OnMousePressed(const MouseEvent& event) {
  if (!IsPointInDivider(event.x()))
    return false;
  drag_info_.initial_mouse_x = event.x();
  drag_info_.initial_divider_x = divider_x_;
  return true;
}

bool SingleSplitView::OnMouseDragged(const MouseEvent& event) {
  if (GetChildViewCount() < 2)
    return false;

  int delta_x = event.x() - drag_info_.initial_mouse_x;
  if (UILayoutIsRightToLeft())
    delta_x *= -1;
  // Honor the minimum size when resizing.
  int new_width = std::max(GetChildViewAt(0)->GetMinimumSize().width(),
                           drag_info_.initial_divider_x + delta_x);

  // And don't let the view get bigger than our width.
  new_width = std::min(width() - kDividerSize, new_width);

  if (new_width != divider_x_) {
    set_divider_x(new_width);
    Layout();
  }
  return true;
}

void SingleSplitView::OnMouseReleased(const MouseEvent& event, bool canceled) {
  if (GetChildViewCount() < 2)
    return;

  if (canceled && drag_info_.initial_divider_x != divider_x_) {
    set_divider_x(drag_info_.initial_divider_x);
    Layout();
  }
}

bool SingleSplitView::IsPointInDivider(int x) {
  if (GetChildViewCount() < 2)
    return false;

  int divider_relative_x =
      x - GetChildViewAt(UILayoutIsRightToLeft() ? 1 : 0)->width();
  return (divider_relative_x >= 0 && divider_relative_x < kDividerSize);
}

}  // namespace views
<|endoftext|>


<commit_before>// RUN: cat %s | %cling 2>&1 | FileCheck %s
// Test Interpreter::lookupFunctionArgs()
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/Decl.h"

#include <cstdio>
using namespace std;

//
//  We need to fetch the global scope declaration,
//  otherwise known as the translation unit decl.
//
const clang::Decl* G = gCling->lookupScope("");
printf("G: 0x%lx\n", (unsigned long) G);
//CHECK: G: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a global function taking no args.
//

.rawInput 1
void f() { int x = 1; }
void a(int v) { int x = v; }
void b(int vi, double vd) { int x = vi; double y = vd; }
void c(int vi, int vj) { int x = vi; int y = vj; }
void c(int vi, double vd) { int x = vi; double y = vd; }
template <class T> void d(T v) { T x = v; }
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void d(int);
template void d(double);
.rawInput 0

const clang::FunctionDecl* F = gCling->lookupFunctionArgs(G, "f", "");
printf("F: 0x%lx\n", (unsigned long) F);
//CHECK-NEXT: F: 0x{{[1-9a-f][0-9a-f]*$}}
F->print(llvm::outs());
//CHECK-NEXT: void f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a global function taking a single int argument.
//

const clang::FunctionDecl* A = gCling->lookupFunctionArgs(G, "a", "0");
printf("A: 0x%lx\n", (unsigned long) A);
//CHECK: A: 0x{{[1-9a-f][0-9a-f]*$}}
A->print(llvm::outs());
//CHECK-NEXT: void a(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a global function taking an int and a double argument.
//

const clang::FunctionDecl* B = gCling->lookupFunctionArgs(G, "b", "0,0.0");
printf("B: 0x%lx\n", (unsigned long) B);
//CHECK: B: 0x{{[1-9a-f][0-9a-f]*$}}
B->print(llvm::outs());
//CHECK-NEXT: void b(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a global overloaded function.
//

const clang::FunctionDecl* C1 = gCling->lookupFunctionArgs(G, "c", "0,0");
printf("C1: 0x%lx\n", (unsigned long) C1);
//CHECK: C1: 0x{{[1-9a-f][0-9a-f]*$}}
C1->print(llvm::outs());
//CHECK-NEXT: void c(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* C2 = gCling->lookupFunctionArgs(G, "c", "0,0.0");
printf("C2: 0x%lx\n", (unsigned long) C2);
//CHECK: C2: 0x{{[1-9a-f][0-9a-f]*$}}
C2->print(llvm::outs());
//CHECK-NEXT: void c(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple global template instantiations.
//

const clang::FunctionDecl* D1 = gCling->lookupFunctionArgs(G, "d<int>", "0");
printf("D1: 0x%lx\n", (unsigned long) D1);
//CHECK: D1: 0x{{[1-9a-f][0-9a-f]*$}}
D1->print(llvm::outs());
//CHECK-NEXT: void d(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* D2 = gCling->lookupFunctionArgs(G, "d<double>", "0.0");
printf("D2: 0x%lx\n", (unsigned long) D2);
//CHECK: D2: 0x{{[1-9a-f][0-9a-f]*$}}
D2->print(llvm::outs());
//CHECK-NEXT: void d(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

.rawInput 1
class B {
   void B_f() { int x = 1; }
   void B_g(int v) { int x = v; }
   void B_h(int vi, double vd) { int x = vi; double y = vd; }
};
class A : public B {
   void A_f() { int x = 1; }
   void A_g(int v) { int x = v; }
   void A_h(int vi, double vd) { int x = vi; double y = vd; }
   void A_j(int vi, int vj) { int x = vi; int y = vj; }
   void A_j(int vi, double vd) { int x = vi; double y = vd; }
   template <class T> void A_k(T v) { T x = v; }
};
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void A::A_k(int);
template void A::A_k(double);
.rawInput 0

const clang::Decl* class_A = gCling->lookupScope("A");
printf("class_A: 0x%lx\n", (unsigned long) class_A);
//CHECK: class_A: 0x{{[1-9a-f][0-9a-f]*$}}
//
const clang::Decl* class_B = gCling->lookupScope("B");
printf("class_B: 0x%lx\n", (unsigned long) class_B);
//CHECK-NEXT: class_B: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a member function taking no args.
//

const clang::FunctionDecl* func_A_f = gCling->lookupFunctionArgs(class_A, "A_f", "");
printf("func_A_f: 0x%lx\n", (unsigned long) func_A_f);
//CHECK-NEXT: func_A_f: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_f->print(llvm::outs());
//CHECK-NEXT: void A_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg.
//

const clang::FunctionDecl* func_A_g = gCling->lookupFunctionArgs(class_A, "A_g", "0");
printf("func_A_g: 0x%lx\n", (unsigned long) func_A_g);
//CHECK: func_A_g: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_g->print(llvm::outs());
//CHECK-NEXT: void A_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument.
//

const clang::FunctionDecl* func_A_h = gCling->lookupFunctionArgs(class_A, "A_h", "0,0.0");
printf("func_A_h: 0x%lx\n", (unsigned long) func_A_h);
//CHECK: func_A_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_h->print(llvm::outs());
//CHECK-NEXT: void A_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding an overloaded member function.
//

const clang::FunctionDecl* func_A_j1 = gCling->lookupFunctionArgs(class_A, "A_j", "0,0");
printf("func_A_j1: 0x%lx\n", (unsigned long) func_A_j1);
//CHECK: func_A_j1: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j1->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* func_A_j2 = gCling->lookupFunctionArgs(class_A, "A_j", "0,0.0");
printf("func_A_j2: 0x%lx\n", (unsigned long) func_A_j2);
//CHECK: func_A_j2: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j2->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a member function taking no args in a base class.
//

const clang::FunctionDecl* func_B_F = gCling->lookupFunctionArgs(class_A, "B_f", "");
printf("func_B_F: 0x%lx\n", (unsigned long) func_B_F);
//CHECK: func_B_F: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_F->print(llvm::outs());
//CHECK-NEXT: void B_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg in a base class.
//

const clang::FunctionDecl* func_B_G = gCling->lookupFunctionArgs(class_A, "B_g", "0");
printf("func_B_G: 0x%lx\n", (unsigned long) func_B_G);
//CHECK: func_B_G: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_G->print(llvm::outs());
//CHECK-NEXT: void B_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument
//  in a base class.
//

const clang::FunctionDecl* func_B_h = gCling->lookupFunctionArgs(class_A, "B_h", "0,0.0");
printf("func_B_h: 0x%lx\n", (unsigned long) func_B_h);
//CHECK: func_B_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_h->print(llvm::outs());
//CHECK-NEXT: void B_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  One final check to make sure we are at the right line in the output.
//

"abc"
//CHECK: (const char [4]) @0x{{[0-9a-f]+}}

<commit_msg>Test finding an overloaded member function in a base class.<commit_after>// RUN: cat %s | %cling 2>&1 | FileCheck %s
// Test Interpreter::lookupFunctionArgs()
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/Decl.h"

#include <cstdio>
using namespace std;

//
//  We need to fetch the global scope declaration,
//  otherwise known as the translation unit decl.
//
const clang::Decl* G = gCling->lookupScope("");
printf("G: 0x%lx\n", (unsigned long) G);
//CHECK: G: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a global function taking no args.
//

.rawInput 1
void f() { int x = 1; }
void a(int v) { int x = v; }
void b(int vi, double vd) { int x = vi; double y = vd; }
void c(int vi, int vj) { int x = vi; int y = vj; }
void c(int vi, double vd) { int x = vi; double y = vd; }
template <class T> void d(T v) { T x = v; }
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void d(int);
template void d(double);
.rawInput 0

const clang::FunctionDecl* F = gCling->lookupFunctionArgs(G, "f", "");
printf("F: 0x%lx\n", (unsigned long) F);
//CHECK-NEXT: F: 0x{{[1-9a-f][0-9a-f]*$}}
F->print(llvm::outs());
//CHECK-NEXT: void f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a global function taking a single int argument.
//

const clang::FunctionDecl* A = gCling->lookupFunctionArgs(G, "a", "0");
printf("A: 0x%lx\n", (unsigned long) A);
//CHECK: A: 0x{{[1-9a-f][0-9a-f]*$}}
A->print(llvm::outs());
//CHECK-NEXT: void a(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a global function taking an int and a double argument.
//

const clang::FunctionDecl* B = gCling->lookupFunctionArgs(G, "b", "0,0.0");
printf("B: 0x%lx\n", (unsigned long) B);
//CHECK: B: 0x{{[1-9a-f][0-9a-f]*$}}
B->print(llvm::outs());
//CHECK-NEXT: void b(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a global overloaded function.
//

const clang::FunctionDecl* C1 = gCling->lookupFunctionArgs(G, "c", "0,0");
printf("C1: 0x%lx\n", (unsigned long) C1);
//CHECK: C1: 0x{{[1-9a-f][0-9a-f]*$}}
C1->print(llvm::outs());
//CHECK-NEXT: void c(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* C2 = gCling->lookupFunctionArgs(G, "c", "0,0.0");
printf("C2: 0x%lx\n", (unsigned long) C2);
//CHECK: C2: 0x{{[1-9a-f][0-9a-f]*$}}
C2->print(llvm::outs());
//CHECK-NEXT: void c(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding simple global template instantiations.
//

const clang::FunctionDecl* D1 = gCling->lookupFunctionArgs(G, "d<int>", "0");
printf("D1: 0x%lx\n", (unsigned long) D1);
//CHECK: D1: 0x{{[1-9a-f][0-9a-f]*$}}
D1->print(llvm::outs());
//CHECK-NEXT: void d(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

const clang::FunctionDecl* D2 = gCling->lookupFunctionArgs(G, "d<double>", "0.0");
printf("D2: 0x%lx\n", (unsigned long) D2);
//CHECK: D2: 0x{{[1-9a-f][0-9a-f]*$}}
D2->print(llvm::outs());
//CHECK-NEXT: void d(double v) {
//CHECK-NEXT:     double x = v;
//CHECK-NEXT: }

.rawInput 1
class B {
   void B_f() { int x = 1; }
   void B_g(int v) { int x = v; }
   void B_h(int vi, double vd) { int x = vi; double y = vd; }
   void B_j(int vi, int vj) { int x = vi; int y = vj; }
   void B_j(int vi, double vd) { int x = vi; double y = vd; }
};
class A : public B {
   void A_f() { int x = 1; }
   void A_g(int v) { int x = v; }
   void A_h(int vi, double vd) { int x = vi; double y = vd; }
   void A_j(int vi, int vj) { int x = vi; int y = vj; }
   void A_j(int vi, double vd) { int x = vi; double y = vd; }
   template <class T> void A_k(T v) { T x = v; }
};
// Note: In CINT, looking up a class template specialization causes
//       instantiation, but looking up a function template specialization
//       does not, so we explicitly request the instantiations we are
//       going to lookup so they will be there to find.
template void A::A_k(int);
template void A::A_k(double);
.rawInput 0

const clang::Decl* class_A = gCling->lookupScope("A");
printf("class_A: 0x%lx\n", (unsigned long) class_A);
//CHECK: class_A: 0x{{[1-9a-f][0-9a-f]*$}}
//
const clang::Decl* class_B = gCling->lookupScope("B");
printf("class_B: 0x%lx\n", (unsigned long) class_B);
//CHECK-NEXT: class_B: 0x{{[1-9a-f][0-9a-f]*$}}

//
//  Test finding a member function taking no args.
//

const clang::FunctionDecl* func_A_f = gCling->lookupFunctionArgs(class_A, "A_f", "");
printf("func_A_f: 0x%lx\n", (unsigned long) func_A_f);
//CHECK-NEXT: func_A_f: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_f->print(llvm::outs());
//CHECK-NEXT: void A_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg.
//

const clang::FunctionDecl* func_A_g = gCling->lookupFunctionArgs(class_A, "A_g", "0");
printf("func_A_g: 0x%lx\n", (unsigned long) func_A_g);
//CHECK: func_A_g: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_g->print(llvm::outs());
//CHECK-NEXT: void A_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument.
//

const clang::FunctionDecl* func_A_h = gCling->lookupFunctionArgs(class_A, "A_h", "0,0.0");
printf("func_A_h: 0x%lx\n", (unsigned long) func_A_h);
//CHECK: func_A_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_h->print(llvm::outs());
//CHECK-NEXT: void A_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding an overloaded member function.
//

const clang::FunctionDecl* func_A_j1 = gCling->lookupFunctionArgs(class_A, "A_j", "0,0");
printf("func_A_j1: 0x%lx\n", (unsigned long) func_A_j1);
//CHECK: func_A_j1: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j1->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* func_A_j2 = gCling->lookupFunctionArgs(class_A, "A_j", "0,0.0");
printf("func_A_j2: 0x%lx\n", (unsigned long) func_A_j2);
//CHECK: func_A_j2: 0x{{[1-9a-f][0-9a-f]*$}}
func_A_j2->print(llvm::outs());
//CHECK-NEXT: void A_j(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding a member function taking no args in a base class.
//

const clang::FunctionDecl* func_B_F = gCling->lookupFunctionArgs(class_A, "B_f", "");
printf("func_B_F: 0x%lx\n", (unsigned long) func_B_F);
//CHECK: func_B_F: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_F->print(llvm::outs());
//CHECK-NEXT: void B_f() {
//CHECK-NEXT:     int x = 1;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int arg in a base class.
//

const clang::FunctionDecl* func_B_G = gCling->lookupFunctionArgs(class_A, "B_g", "0");
printf("func_B_G: 0x%lx\n", (unsigned long) func_B_G);
//CHECK: func_B_G: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_G->print(llvm::outs());
//CHECK-NEXT: void B_g(int v) {
//CHECK-NEXT:     int x = v;
//CHECK-NEXT: }

//
//  Test finding a member function taking an int and a double argument
//  in a base class.
//

const clang::FunctionDecl* func_B_h = gCling->lookupFunctionArgs(class_A, "B_h", "0,0.0");
printf("func_B_h: 0x%lx\n", (unsigned long) func_B_h);
//CHECK: func_B_h: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_h->print(llvm::outs());
//CHECK-NEXT: void B_h(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  Test finding an overloaded member function in a base class.
//

const clang::FunctionDecl* func_B_j1 = gCling->lookupFunctionArgs(class_A, "B_j", "0,0");
printf("func_B_j1: 0x%lx\n", (unsigned long) func_B_j1);
//CHECK: func_B_j1: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_j1->print(llvm::outs());
//CHECK-NEXT: void B_j(int vi, int vj) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     int y = vj;
//CHECK-NEXT: }

const clang::FunctionDecl* func_B_j2 = gCling->lookupFunctionArgs(class_A, "B_j", "0,0.0");
printf("func_B_j2: 0x%lx\n", (unsigned long) func_B_j2);
//CHECK: func_B_j2: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_j2->print(llvm::outs());
//CHECK-NEXT: void B_j(int vi, double vd) {
//CHECK-NEXT:     int x = vi;
//CHECK-NEXT:     double y = vd;
//CHECK-NEXT: }

//
//  One final check to make sure we are at the right line in the output.
//

"abc"
//CHECK: (const char [4]) @0x{{[0-9a-f]+}}

<|endoftext|>


<commit_before>/*
 * typeconv.hpp
 *  a class to convert types by routing through std::string / std::wstring
 *
 *  written by janus_wel<janus.wel.3@gmail.com>
 *  This source code is in the public domain, and has NO WARRANTY.
 * */

#ifndef TYPECONV_HPP
#define TYPECONV_HPP

#include <locale>
#include <sstream>
#include <string>
#include <vector>

#include "string.hpp"

namespace util {
    namespace string {
        // definitions of character traits
        template<typename Char> struct char_traits {};
        template<> struct char_traits<char> {
            typedef char                char_type;
            static const char_type* null() { return ""; }
            static const char_type* space() { return " "; }
        };
        template<> struct char_traits<wchar_t> {
            typedef wchar_t             char_type;
            static const char_type* null() { return L""; }
            static const char_type* space() { return L" "; }
        };

        // type converter
        template<typename Char, typename Traits = char_traits<Char> >
            class basic_typeconverter : public std::basic_stringstream<Char> {
                private:
                    // for convenience
                    typedef Char                            char_type;
                    typedef std::basic_string<char_type>    string_type;

                public:
                    // constructor
                    basic_typeconverter(void) {}
                    explicit basic_typeconverter(std::locale loc) {
                        this->imbue(loc);
                    }

                    // specified type -> std::basic_string
                    // This can be omitted specifying T because tye type
                    // inference always works.
                    template<typename T>
                        string_type strfrom(T src) {
                            this->clear();
                            this->str(Traits::null());

                            *this << src;
                            return this->str();
                        }

                    // std::basic_string -> specified type
                    // This must be specified T
                    template<typename T>
                        T strto(const string_type& src) {
                            this->clear();

                            this->str(src);
                            T dst;
                            *this >> dst;
                            return dst;
                        }

                    // some elements of any type -> std::basic_string
                    template<typename InputIterator>
                        string_type join(
                                InputIterator first, InputIterator last,
                                const string_type& delimiter = Traits::space()) {
                            if (first == last)
                                return string_type(Traits::null());

                            this->clear();
                            this->str(Traits::null());

                            *this << *first++;
                            while (first != last) *this << delimiter << *first++;
                            return this->str();
                        }

                    // std::basic_string -> some elements of any type
                    template<typename SequenceContainer>
                        SequenceContainer&
                        split(  const string_type& src,
                                SequenceContainer& result,
                                const char_type* const delimiter) {
                            unsigned int n =
                                util::string::count(src, delimiter);

                            result.resize(n + 1);
                            search_push(src, delimiter, n, result.begin());

                            return result;
                        }

                    // for std::vector
                    template<typename Value>
                        std::vector<Value>&
                        split(  const string_type& src,
                                std::vector<Value>& result,
                                const char_type* const delimiter) {
                            unsigned int n =
                                util::string::count(src, delimiter);

                            result.resize(n + 1);
                            result.reserve(n + 1);
                            search_push(src, delimiter, n, result.begin());

                            return result;
                        }

                protected:
                    // common procedure for split
                    template<typename OutputIterator>
                    void search_push(const string_type& src,
                                const char_type* const delimiter,
                                const unsigned int n,
                                OutputIterator first) {
                        typename string_type::size_type head = 0;
                        typename string_type::size_type tail;
                        for (unsigned int i = 0; i < n + 1; ++i) {
                            tail = src.find(delimiter, head);

                            this->clear();
                            this->str(src.substr(head, tail - head));
                            *this >> *first++;

                            head = tail + 1;
                        }
                    }
            };

        // for convenience
        typedef basic_typeconverter<char>    typeconverter;
        typedef basic_typeconverter<wchar_t> wtypeconverter;
    }
}

#endif // TYPECONV_HPP

<commit_msg>Speed up<commit_after>/*
 * typeconv.hpp
 *  a class to convert types by routing through std::string / std::wstring
 *
 *  written by janus_wel<janus.wel.3@gmail.com>
 *  This source code is in the public domain, and has NO WARRANTY.
 * */

#ifndef TYPECONV_HPP
#define TYPECONV_HPP

#include <locale>
#include <sstream>
#include <string>
#include <vector>

#include "string.hpp"

namespace util {
    namespace string {
        // definitions of character traits
        template<typename Char> struct char_traits {};
        template<> struct char_traits<char> {
            typedef char                char_type;
            static const char_type* null() { return ""; }
            static const char_type* space() { return " "; }
        };
        template<> struct char_traits<wchar_t> {
            typedef wchar_t             char_type;
            static const char_type* null() { return L""; }
            static const char_type* space() { return L" "; }
        };

        // type converter
        template<typename Char, typename Traits = char_traits<Char> >
            class basic_typeconverter : public std::basic_stringstream<Char> {
                private:
                    // for convenience
                    typedef Char                            char_type;
                    typedef std::basic_string<char_type>    string_type;

                public:
                    // constructor
                    basic_typeconverter(void) {}
                    explicit basic_typeconverter(const std::locale& loc) {
                        this->imbue(loc);
                    }

                    // specified type -> std::basic_string
                    // This can be omitted specifying T because tye type
                    // inference always works.
                    template<typename T>
                        string_type strfrom(const T& src) {
                            this->clear();
                            this->str(Traits::null());

                            *this << src;
                            return this->str();
                        }

                    // std::basic_string -> specified type
                    // This must be specified T
                    template<typename T>
                        T strto(const string_type& src) {
                            this->clear();

                            this->str(src);
                            T dst;
                            *this >> dst;
                            return dst;
                        }

                    // some elements of any type -> std::basic_string
                    template<typename InputIterator>
                        string_type join(
                                InputIterator first, InputIterator last,
                                const string_type& delimiter = Traits::space()) {
                            if (first == last)
                                return string_type(Traits::null());

                            this->clear();
                            this->str(Traits::null());

                            *this << *first++;
                            while (first != last) *this << delimiter << *first++;
                            return this->str();
                        }

                    // std::basic_string -> some elements of any type
                    template<typename SequenceContainer>
                        SequenceContainer&
                        split(  const string_type& src,
                                SequenceContainer& result,
                                const char_type* const delimiter) {
                            unsigned int n =
                                util::string::count(src, delimiter);

                            result.resize(n + 1);
                            search_push(src, delimiter, n, result.begin());

                            return result;
                        }

                    // for std::vector
                    template<typename Value>
                        std::vector<Value>&
                        split(  const string_type& src,
                                std::vector<Value>& result,
                                const char_type* const delimiter) {
                            unsigned int n =
                                util::string::count(src, delimiter);

                            result.resize(n + 1);
                            result.reserve(n + 1);
                            search_push(src, delimiter, n, result.begin());

                            return result;
                        }

                protected:
                    // common procedure for split
                    template<typename OutputIterator>
                    void search_push(const string_type& src,
                                const char_type* const delimiter,
                                const unsigned int n,
                                OutputIterator first) {
                        typename string_type::size_type head = 0;
                        typename string_type::size_type tail;
                        for (unsigned int i = 0; i < n + 1; ++i) {
                            tail = src.find(delimiter, head);

                            this->clear();
                            this->str(src.substr(head, tail - head));
                            *this >> *first++;

                            head = tail + 1;
                        }
                    }
            };

        // for convenience
        typedef basic_typeconverter<char>    typeconverter;
        typedef basic_typeconverter<wchar_t> wtypeconverter;
    }
}

#endif // TYPECONV_HPP

<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>
#include <my_pthread.h>

#include <ndb_cluster_connection.hpp>
#include <TransporterFacade.hpp>
#include <NdbOut.hpp>
#include <NdbSleep.h>
#include <NdbThread.h>
#include <ndb_limits.h>
#include <ConfigRetriever.hpp>
#include <ndb_version.h>

static int g_run_connect_thread= 0;

Ndb_cluster_connection::Ndb_cluster_connection(const char *connect_string)
{
  m_facade= TransporterFacade::theFacadeInstance= new TransporterFacade();
  if (connect_string)
    m_connect_string= strdup(connect_string);
  else
    m_connect_string= 0;
  m_config_retriever= 0;
  m_connect_thread= 0;
  m_connect_callback= 0;
}

extern "C" pthread_handler_decl(run_ndb_cluster_connection_connect_thread, me)
{
  my_thread_init();
  g_run_connect_thread= 1;
  ((Ndb_cluster_connection*) me)->connect_thread();
  my_thread_end();
  NdbThread_Exit(0);
  return me;
}

void Ndb_cluster_connection::connect_thread()
{
  DBUG_ENTER("Ndb_cluster_connection::connect_thread");
  int r;
  do {
    if ((r = connect(1)) == 0)
      break;
    if (r == -1) {
      printf("Ndb_cluster_connection::connect_thread error\n");
      DBUG_ASSERT(false);
      g_run_connect_thread= 0;
    }
  } while (g_run_connect_thread);
  if (m_connect_callback)
    (*m_connect_callback)();
  DBUG_VOID_RETURN;
}

int Ndb_cluster_connection::start_connect_thread(int (*connect_callback)(void))
{
  int r;
  DBUG_ENTER("Ndb_cluster_connection::start_connect_thread");
  m_connect_callback= connect_callback;
  if ((r = connect(1)) == 1)
    m_connect_thread= NdbThread_Create(run_ndb_cluster_connection_connect_thread,
				       (void**)this,
				       32768,
				       "ndb_cluster_connection",
				       NDB_THREAD_PRIO_LOW);
  else if (r < 0)
    DBUG_RETURN(-1)
  else if (m_connect_callback)
    (*m_connect_callback)();
  DBUG_RETURN(0);
}

int Ndb_cluster_connection::connect(int reconnect)
{
  DBUG_ENTER("Ndb_cluster_connection::connect");
  const char* error = 0;
  do {
    if (m_config_retriever == 0)
    {
      m_config_retriever= new ConfigRetriever(NDB_VERSION, NODE_TYPE_API);
      m_config_retriever->setConnectString(m_connect_string);
      if(m_config_retriever->init() == -1)
	break;
    }
    else
      if (reconnect == 0)
	DBUG_RETURN(0);
    if (reconnect)
    {
      int r= m_config_retriever->do_connect(1);
      if (r == 1)
	DBUG_RETURN(1); // mgmt server not up yet
      if (r == -1)
	break;
    }
    else
      if(m_config_retriever->do_connect() == -1)
	break;
    Uint32 nodeId = m_config_retriever->allocNodeId();
    for(Uint32 i = 0; nodeId == 0 && i<5; i++){
      NdbSleep_SecSleep(3);
      nodeId = m_config_retriever->allocNodeId();
    }
    if(nodeId == 0)
      break;
    ndb_mgm_configuration * props = m_config_retriever->getConfig();
    if(props == 0)
      break;
    m_facade->start_instance(nodeId, props);
    ndb_mgm_destroy_configuration(props);
    m_facade->connected();
    DBUG_RETURN(0);
  } while(0);

  ndbout << "Configuration error: ";
  const char* erString = m_config_retriever->getErrorString();
  if (erString == 0) {
    erString = "No error specified!";
  }
  ndbout << erString << endl;
  DBUG_RETURN(-1);
}

Ndb_cluster_connection::~Ndb_cluster_connection()
{
  if (m_connect_thread)
  {
    void *status;
    g_run_connect_thread= 0;
    NdbThread_WaitFor(m_connect_thread, &status);
    NdbThread_Destroy(&m_connect_thread);
    m_connect_thread= 0;
  }
  if (m_facade != 0)
  {
    delete m_facade;
    if (m_facade != TransporterFacade::theFacadeInstance)
      abort();
    TransporterFacade::theFacadeInstance= 0;
  }
  if (m_connect_string)
    free(m_connect_string);
  if (m_config_retriever)
    delete m_config_retriever;
}

<commit_msg>Fix braces wrt to DBUG_xxx<commit_after>/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <ndb_global.h>
#include <my_pthread.h>

#include <ndb_cluster_connection.hpp>
#include <TransporterFacade.hpp>
#include <NdbOut.hpp>
#include <NdbSleep.h>
#include <NdbThread.h>
#include <ndb_limits.h>
#include <ConfigRetriever.hpp>
#include <ndb_version.h>

static int g_run_connect_thread= 0;

Ndb_cluster_connection::Ndb_cluster_connection(const char *connect_string)
{
  m_facade= TransporterFacade::theFacadeInstance= new TransporterFacade();
  if (connect_string)
    m_connect_string= strdup(connect_string);
  else
    m_connect_string= 0;
  m_config_retriever= 0;
  m_connect_thread= 0;
  m_connect_callback= 0;
}

extern "C" pthread_handler_decl(run_ndb_cluster_connection_connect_thread, me)
{
  my_thread_init();
  g_run_connect_thread= 1;
  ((Ndb_cluster_connection*) me)->connect_thread();
  my_thread_end();
  NdbThread_Exit(0);
  return me;
}

void Ndb_cluster_connection::connect_thread()
{
  DBUG_ENTER("Ndb_cluster_connection::connect_thread");
  int r;
  do {
    if ((r = connect(1)) == 0)
      break;
    if (r == -1) {
      printf("Ndb_cluster_connection::connect_thread error\n");
      DBUG_ASSERT(false);
      g_run_connect_thread= 0;
    }
  } while (g_run_connect_thread);
  if (m_connect_callback)
    (*m_connect_callback)();
  DBUG_VOID_RETURN;
}

int Ndb_cluster_connection::start_connect_thread(int (*connect_callback)(void))
{
  int r;
  DBUG_ENTER("Ndb_cluster_connection::start_connect_thread");
  m_connect_callback= connect_callback;
  if ((r = connect(1)) == 1)
  {
    m_connect_thread= NdbThread_Create(run_ndb_cluster_connection_connect_thread,
				       (void**)this,
				       32768,
				       "ndb_cluster_connection",
				       NDB_THREAD_PRIO_LOW);
  }
  else if (r < 0)
  {
    DBUG_RETURN(-1);
  }
  else if (m_connect_callback)
  {
    (*m_connect_callback)();
  }
  DBUG_RETURN(0);
}

int Ndb_cluster_connection::connect(int reconnect)
{
  DBUG_ENTER("Ndb_cluster_connection::connect");
  const char* error = 0;
  do {
    if (m_config_retriever == 0)
    {
      m_config_retriever= new ConfigRetriever(NDB_VERSION, NODE_TYPE_API);
      m_config_retriever->setConnectString(m_connect_string);
      if(m_config_retriever->init() == -1)
	break;
    }
    else
      if (reconnect == 0)
	DBUG_RETURN(0);
    if (reconnect)
    {
      int r= m_config_retriever->do_connect(1);
      if (r == 1)
	DBUG_RETURN(1); // mgmt server not up yet
      if (r == -1)
	break;
    }
    else
      if(m_config_retriever->do_connect() == -1)
	break;
    Uint32 nodeId = m_config_retriever->allocNodeId();
    for(Uint32 i = 0; nodeId == 0 && i<5; i++){
      NdbSleep_SecSleep(3);
      nodeId = m_config_retriever->allocNodeId();
    }
    if(nodeId == 0)
      break;
    ndb_mgm_configuration * props = m_config_retriever->getConfig();
    if(props == 0)
      break;
    m_facade->start_instance(nodeId, props);
    ndb_mgm_destroy_configuration(props);
    m_facade->connected();
    DBUG_RETURN(0);
  } while(0);

  ndbout << "Configuration error: ";
  const char* erString = m_config_retriever->getErrorString();
  if (erString == 0) {
    erString = "No error specified!";
  }
  ndbout << erString << endl;
  DBUG_RETURN(-1);
}

Ndb_cluster_connection::~Ndb_cluster_connection()
{
  if (m_connect_thread)
  {
    void *status;
    g_run_connect_thread= 0;
    NdbThread_WaitFor(m_connect_thread, &status);
    NdbThread_Destroy(&m_connect_thread);
    m_connect_thread= 0;
  }
  if (m_facade != 0)
  {
    delete m_facade;
    if (m_facade != TransporterFacade::theFacadeInstance)
      abort();
    TransporterFacade::theFacadeInstance= 0;
  }
  if (m_connect_string)
    free(m_connect_string);
  if (m_config_retriever)
    delete m_config_retriever;
}

<|endoftext|>


<commit_before><commit_msg>effectively expand init_header into member init list<commit_after><|endoftext|>