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

#include "chrome/browser/printing/print_dialog_gtk.h"

#include <fcntl.h>
#include <gtk/gtkpagesetupunixdialog.h>
#include <gtk/gtkprintjob.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "printing/metafile.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings_initializer_gtk.h"

using printing::PageRanges;
using printing::PrintSettings;

namespace {

// Helper class to track GTK printers.
class GtkPrinterList {
 public:
  GtkPrinterList() : default_printer_(NULL) {
    gtk_enumerate_printers((GtkPrinterFunc)SetPrinter, this, NULL, TRUE);
  }

  ~GtkPrinterList() {
    for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
         it < printers_.end(); ++it) {
      g_object_unref(*it);
    }
  }

  GtkPrinter* default_printer() {
    return default_printer_;
  }

  GtkPrinter* GetPrinterWithName(const char* name) {
    if (!name || !*name)
      return NULL;

    for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
         it < printers_.end(); ++it) {
      if (strcmp(name, gtk_printer_get_name(*it)) == 0) {
        return *it;
      }
    }

    return NULL;
  }

 private:
  // Callback function used by gtk_enumerate_printers() to get all printer.
  static bool SetPrinter(GtkPrinter* printer, GtkPrinterList* printer_list) {
    if (gtk_printer_is_default(printer))
      printer_list->default_printer_ = printer;

    g_object_ref(printer);
    printer_list->printers_.push_back(printer);

    return false;
  }

  std::vector<GtkPrinter*> printers_;
  GtkPrinter* default_printer_;
};

}  // namespace

// static
printing::PrintDialogGtkInterface* PrintDialogGtk::CreatePrintDialog(
    PrintingContextCairo* context) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return new PrintDialogGtk(context);
}

PrintDialogGtk::PrintDialogGtk(PrintingContextCairo* context)
    : callback_(NULL),
      context_(context),
      dialog_(NULL),
      gtk_settings_(NULL),
      page_setup_(NULL),
      printer_(NULL) {
}

PrintDialogGtk::~PrintDialogGtk() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (dialog_) {
    gtk_widget_destroy(dialog_);
    dialog_ = NULL;
  }
  if (gtk_settings_) {
    g_object_unref(gtk_settings_);
    gtk_settings_ = NULL;
  }
  if (page_setup_) {
    g_object_unref(page_setup_);
    page_setup_ = NULL;
  }
  if (printer_) {
    g_object_unref(printer_);
    printer_ = NULL;
  }
}

void PrintDialogGtk::UseDefaultSettings() {
  DCHECK(!save_document_event_.get());
  DCHECK(!page_setup_);

  // |gtk_settings_| is a new object.
  gtk_settings_ = gtk_print_settings_new();

  scoped_ptr<GtkPrinterList> printer_list(new GtkPrinterList);
  printer_ = printer_list->default_printer();
  if (printer_) {
    g_object_ref(printer_);
    gtk_print_settings_set_printer(gtk_settings_,
                                   gtk_printer_get_name(printer_));
#if GTK_CHECK_VERSION(2, 14, 0)
    page_setup_ = gtk_printer_get_default_page_size(printer_);
#endif
  }

  if (!page_setup_)
    page_setup_ = gtk_page_setup_new();

  // No page range to initialize for default settings.
  PageRanges ranges_vector;
  InitPrintSettings(ranges_vector);
}

bool PrintDialogGtk::UpdateSettings(const DictionaryValue& settings,
                                    const printing::PageRanges& ranges) {
  std::string printer_name;
  settings.GetString(printing::kSettingPrinterName, &printer_name);

  scoped_ptr<GtkPrinterList> printer_list(new GtkPrinterList);
  printer_ = printer_list->GetPrinterWithName(printer_name.c_str());
  if (!printer_)
    return false;
  g_object_ref(printer_);
  gtk_print_settings_set_printer(gtk_settings_,
                                 gtk_printer_get_name(printer_));

  bool landscape;
  if (!settings.GetBoolean(printing::kSettingLandscape, &landscape))
    return false;

  gtk_print_settings_set_orientation(
      gtk_settings_,
      landscape ? GTK_PAGE_ORIENTATION_LANDSCAPE :
                  GTK_PAGE_ORIENTATION_PORTRAIT);

  int copies;
  if (!settings.GetInteger(printing::kSettingCopies, &copies))
    return false;
  gtk_print_settings_set_n_copies(gtk_settings_, copies);

  bool collate;
  if (!settings.GetBoolean(printing::kSettingCollate, &collate))
    return false;
  gtk_print_settings_set_collate(gtk_settings_, collate);

  // TODO(thestig) Color: gtk_print_settings_set_color() does not work.
  // TODO(thestig) Duplex: gtk_print_settings_set_duplex() does not work.

  InitPrintSettings(ranges);
  return true;
}

void PrintDialogGtk::ShowDialog(
    PrintingContextCairo::PrintSettingsCallback* callback) {
  DCHECK(!save_document_event_.get());

  callback_ = callback;

  GtkWindow* parent = BrowserList::GetLastActive()->window()->GetNativeHandle();
  // TODO(estade): We need a window title here.
  dialog_ = gtk_print_unix_dialog_new(NULL, parent);

  // Set modal so user cannot focus the same tab and press print again.
  gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);

  // Since we only generate PDF, only show printers that support PDF.
  // TODO(thestig) Add more capabilities to support?
  GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
      GTK_PRINT_CAPABILITY_GENERATE_PDF |
      GTK_PRINT_CAPABILITY_PAGE_SET |
      GTK_PRINT_CAPABILITY_COPIES |
      GTK_PRINT_CAPABILITY_COLLATE |
      GTK_PRINT_CAPABILITY_REVERSE);
  gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog_),
                                                cap);
#if GTK_CHECK_VERSION(2, 18, 0)
  gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
                                             TRUE);
#endif
  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
  gtk_widget_show(dialog_);
}

void PrintDialogGtk::PrintDocument(const printing::Metafile* metafile,
                                   const string16& document_name) {
  // This runs on the print worker thread, does not block the UI thread.
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));

  // The document printing tasks can outlive the PrintingContext that created
  // this dialog.
  AddRef();
  DCHECK(!save_document_event_.get());
  save_document_event_.reset(new base::WaitableEvent(false, false));

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this,
                        &PrintDialogGtk::SaveDocumentToDisk,
                        metafile,
                        document_name));
  // Wait for SaveDocumentToDisk() to finish.
  save_document_event_->Wait();
}

void PrintDialogGtk::AddRefToDialog() {
  AddRef();
}

void PrintDialogGtk::ReleaseDialog() {
  Release();
}

void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
  gtk_widget_hide(dialog_);

  switch (response_id) {
    case GTK_RESPONSE_OK: {
      if (gtk_settings_)
        g_object_unref(gtk_settings_);
      gtk_settings_ = gtk_print_unix_dialog_get_settings(
          GTK_PRINT_UNIX_DIALOG(dialog_));

      if (printer_)
        g_object_unref(printer_);
      printer_ = gtk_print_unix_dialog_get_selected_printer(
          GTK_PRINT_UNIX_DIALOG(dialog_));
      g_object_ref(printer_);

      if (page_setup_)
        g_object_unref(page_setup_);
      page_setup_ = gtk_print_unix_dialog_get_page_setup(
          GTK_PRINT_UNIX_DIALOG(dialog_));
      g_object_ref(page_setup_);

      // Handle page ranges.
      PageRanges ranges_vector;
      gint num_ranges;
      GtkPageRange* gtk_range =
          gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
      if (gtk_range) {
        for (int i = 0; i < num_ranges; ++i) {
          printing::PageRange range;
          range.from = gtk_range[i].start;
          range.to = gtk_range[i].end;
          ranges_vector.push_back(range);
        }
        g_free(gtk_range);
      }

      PrintSettings settings;
      printing::PrintSettingsInitializerGtk::InitPrintSettings(
          gtk_settings_, page_setup_, ranges_vector, false, &settings);
      context_->InitWithSettings(settings);
      callback_->Run(PrintingContextCairo::OK);
      callback_ = NULL;
      return;
    }
    case GTK_RESPONSE_DELETE_EVENT:  // Fall through.
    case GTK_RESPONSE_CANCEL: {
      callback_->Run(PrintingContextCairo::CANCEL);
      callback_ = NULL;
      return;
    }
    case GTK_RESPONSE_APPLY:
    default: {
      NOTREACHED();
    }
  }
}

void PrintDialogGtk::SaveDocumentToDisk(const printing::Metafile* metafile,
                                        const string16& document_name) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  bool error = false;
  if (!file_util::CreateTemporaryFile(&path_to_pdf_)) {
    LOG(ERROR) << "Creating temporary file failed";
    error = true;
  }

  if (!error && !metafile->SaveTo(path_to_pdf_)) {
    LOG(ERROR) << "Saving metafile failed";
    file_util::Delete(path_to_pdf_, false);
    error = true;
  }

  // Done saving, let PrintDialogGtk::PrintDocument() continue.
  save_document_event_->Signal();

  if (error) {
    // Matches AddRef() in PrintDocument();
    Release();
  } else {
    // No errors, continue printing.
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(this,
                          &PrintDialogGtk::SendDocumentToPrinter,
                          document_name));
  }
}

void PrintDialogGtk::SendDocumentToPrinter(const string16& document_name) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If |printer_| is NULL then somehow the GTK printer list changed out under
  // us. In which case, just bail out.
  if (!printer_) {
    // Matches AddRef() in PrintDocument();
    Release();
    return;
  }

  GtkPrintJob* print_job = gtk_print_job_new(
      UTF16ToUTF8(document_name).c_str(),
      printer_,
      gtk_settings_,
      page_setup_);
  gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(), NULL);
  gtk_print_job_send(print_job, OnJobCompletedThunk, this, NULL);
}

// static
void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job,
                                         gpointer user_data,
                                         GError* error) {
  static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
}

void PrintDialogGtk::OnJobCompleted(GtkPrintJob* print_job, GError* error) {
  if (error)
    LOG(ERROR) << "Printing failed: " << error->message;
  if (print_job)
    g_object_unref(print_job);
  base::FileUtilProxy::Delete(
      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
      path_to_pdf_,
      false,
      NULL);
  // Printing finished. Matches AddRef() in PrintDocument();
  Release();
}

void PrintDialogGtk::InitPrintSettings(const PageRanges& page_ranges) {
  PrintSettings settings;
  printing::PrintSettingsInitializerGtk::InitPrintSettings(
      gtk_settings_, page_setup_, page_ranges, false, &settings);
  context_->InitWithSettings(settings);
}
<commit_msg>Linux Printing: Continue trying to update settings even if we cannot find the printer.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_dialog_gtk.h"

#include <fcntl.h>
#include <gtk/gtkpagesetupunixdialog.h>
#include <gtk/gtkprintjob.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>
#include <vector>

#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "printing/metafile.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings_initializer_gtk.h"

using printing::PageRanges;
using printing::PrintSettings;

namespace {

// Helper class to track GTK printers.
class GtkPrinterList {
 public:
  GtkPrinterList() : default_printer_(NULL) {
    gtk_enumerate_printers((GtkPrinterFunc)SetPrinter, this, NULL, TRUE);
  }

  ~GtkPrinterList() {
    for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
         it < printers_.end(); ++it) {
      g_object_unref(*it);
    }
  }

  // Can return NULL if there's no default printer. E.g. Printer on a laptop
  // is "home_printer", but the laptop is at work.
  GtkPrinter* default_printer() {
    return default_printer_;
  }

  // Can return NULL if the printer cannot be found due to:
  // - Printer list out of sync with printer dialog UI.
  // - Querying for non-existant printers like 'Print to PDF'.
  GtkPrinter* GetPrinterWithName(const char* name) {
    if (!name || !*name)
      return NULL;

    for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
         it < printers_.end(); ++it) {
      if (strcmp(name, gtk_printer_get_name(*it)) == 0) {
        return *it;
      }
    }

    return NULL;
  }

 private:
  // Callback function used by gtk_enumerate_printers() to get all printer.
  static bool SetPrinter(GtkPrinter* printer, GtkPrinterList* printer_list) {
    if (gtk_printer_is_default(printer))
      printer_list->default_printer_ = printer;

    g_object_ref(printer);
    printer_list->printers_.push_back(printer);

    return false;
  }

  std::vector<GtkPrinter*> printers_;
  GtkPrinter* default_printer_;
};

}  // namespace

// static
printing::PrintDialogGtkInterface* PrintDialogGtk::CreatePrintDialog(
    PrintingContextCairo* context) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return new PrintDialogGtk(context);
}

PrintDialogGtk::PrintDialogGtk(PrintingContextCairo* context)
    : callback_(NULL),
      context_(context),
      dialog_(NULL),
      gtk_settings_(NULL),
      page_setup_(NULL),
      printer_(NULL) {
}

PrintDialogGtk::~PrintDialogGtk() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (dialog_) {
    gtk_widget_destroy(dialog_);
    dialog_ = NULL;
  }
  if (gtk_settings_) {
    g_object_unref(gtk_settings_);
    gtk_settings_ = NULL;
  }
  if (page_setup_) {
    g_object_unref(page_setup_);
    page_setup_ = NULL;
  }
  if (printer_) {
    g_object_unref(printer_);
    printer_ = NULL;
  }
}

void PrintDialogGtk::UseDefaultSettings() {
  DCHECK(!save_document_event_.get());
  DCHECK(!page_setup_);

  // |gtk_settings_| is a new object.
  gtk_settings_ = gtk_print_settings_new();

  scoped_ptr<GtkPrinterList> printer_list(new GtkPrinterList);
  printer_ = printer_list->default_printer();
  if (printer_) {
    g_object_ref(printer_);
    gtk_print_settings_set_printer(gtk_settings_,
                                   gtk_printer_get_name(printer_));
#if GTK_CHECK_VERSION(2, 14, 0)
    page_setup_ = gtk_printer_get_default_page_size(printer_);
#endif
  }

  if (!page_setup_)
    page_setup_ = gtk_page_setup_new();

  // No page range to initialize for default settings.
  PageRanges ranges_vector;
  InitPrintSettings(ranges_vector);
}

bool PrintDialogGtk::UpdateSettings(const DictionaryValue& settings,
                                    const printing::PageRanges& ranges) {
  std::string printer_name;
  settings.GetString(printing::kSettingPrinterName, &printer_name);

  scoped_ptr<GtkPrinterList> printer_list(new GtkPrinterList);
  printer_ = printer_list->GetPrinterWithName(printer_name.c_str());
  if (printer_) {
    g_object_ref(printer_);
    gtk_print_settings_set_printer(gtk_settings_,
                                   gtk_printer_get_name(printer_));
  }

  bool landscape;
  if (!settings.GetBoolean(printing::kSettingLandscape, &landscape))
    return false;

  gtk_print_settings_set_orientation(
      gtk_settings_,
      landscape ? GTK_PAGE_ORIENTATION_LANDSCAPE :
                  GTK_PAGE_ORIENTATION_PORTRAIT);

  int copies;
  if (!settings.GetInteger(printing::kSettingCopies, &copies))
    return false;
  gtk_print_settings_set_n_copies(gtk_settings_, copies);

  bool collate;
  if (!settings.GetBoolean(printing::kSettingCollate, &collate))
    return false;
  gtk_print_settings_set_collate(gtk_settings_, collate);

  // TODO(thestig) Color: gtk_print_settings_set_color() does not work.
  // TODO(thestig) Duplex: gtk_print_settings_set_duplex() does not work.

  InitPrintSettings(ranges);
  return true;
}

void PrintDialogGtk::ShowDialog(
    PrintingContextCairo::PrintSettingsCallback* callback) {
  DCHECK(!save_document_event_.get());

  callback_ = callback;

  GtkWindow* parent = BrowserList::GetLastActive()->window()->GetNativeHandle();
  // TODO(estade): We need a window title here.
  dialog_ = gtk_print_unix_dialog_new(NULL, parent);

  // Set modal so user cannot focus the same tab and press print again.
  gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);

  // Since we only generate PDF, only show printers that support PDF.
  // TODO(thestig) Add more capabilities to support?
  GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
      GTK_PRINT_CAPABILITY_GENERATE_PDF |
      GTK_PRINT_CAPABILITY_PAGE_SET |
      GTK_PRINT_CAPABILITY_COPIES |
      GTK_PRINT_CAPABILITY_COLLATE |
      GTK_PRINT_CAPABILITY_REVERSE);
  gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog_),
                                                cap);
#if GTK_CHECK_VERSION(2, 18, 0)
  gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
                                             TRUE);
#endif
  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
  gtk_widget_show(dialog_);
}

void PrintDialogGtk::PrintDocument(const printing::Metafile* metafile,
                                   const string16& document_name) {
  // This runs on the print worker thread, does not block the UI thread.
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));

  // The document printing tasks can outlive the PrintingContext that created
  // this dialog.
  AddRef();
  DCHECK(!save_document_event_.get());
  save_document_event_.reset(new base::WaitableEvent(false, false));

  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableMethod(this,
                        &PrintDialogGtk::SaveDocumentToDisk,
                        metafile,
                        document_name));
  // Wait for SaveDocumentToDisk() to finish.
  save_document_event_->Wait();
}

void PrintDialogGtk::AddRefToDialog() {
  AddRef();
}

void PrintDialogGtk::ReleaseDialog() {
  Release();
}

void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
  gtk_widget_hide(dialog_);

  switch (response_id) {
    case GTK_RESPONSE_OK: {
      if (gtk_settings_)
        g_object_unref(gtk_settings_);
      gtk_settings_ = gtk_print_unix_dialog_get_settings(
          GTK_PRINT_UNIX_DIALOG(dialog_));

      if (printer_)
        g_object_unref(printer_);
      printer_ = gtk_print_unix_dialog_get_selected_printer(
          GTK_PRINT_UNIX_DIALOG(dialog_));
      g_object_ref(printer_);

      if (page_setup_)
        g_object_unref(page_setup_);
      page_setup_ = gtk_print_unix_dialog_get_page_setup(
          GTK_PRINT_UNIX_DIALOG(dialog_));
      g_object_ref(page_setup_);

      // Handle page ranges.
      PageRanges ranges_vector;
      gint num_ranges;
      GtkPageRange* gtk_range =
          gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
      if (gtk_range) {
        for (int i = 0; i < num_ranges; ++i) {
          printing::PageRange range;
          range.from = gtk_range[i].start;
          range.to = gtk_range[i].end;
          ranges_vector.push_back(range);
        }
        g_free(gtk_range);
      }

      PrintSettings settings;
      printing::PrintSettingsInitializerGtk::InitPrintSettings(
          gtk_settings_, page_setup_, ranges_vector, false, &settings);
      context_->InitWithSettings(settings);
      callback_->Run(PrintingContextCairo::OK);
      callback_ = NULL;
      return;
    }
    case GTK_RESPONSE_DELETE_EVENT:  // Fall through.
    case GTK_RESPONSE_CANCEL: {
      callback_->Run(PrintingContextCairo::CANCEL);
      callback_ = NULL;
      return;
    }
    case GTK_RESPONSE_APPLY:
    default: {
      NOTREACHED();
    }
  }
}

void PrintDialogGtk::SaveDocumentToDisk(const printing::Metafile* metafile,
                                        const string16& document_name) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  bool error = false;
  if (!file_util::CreateTemporaryFile(&path_to_pdf_)) {
    LOG(ERROR) << "Creating temporary file failed";
    error = true;
  }

  if (!error && !metafile->SaveTo(path_to_pdf_)) {
    LOG(ERROR) << "Saving metafile failed";
    file_util::Delete(path_to_pdf_, false);
    error = true;
  }

  // Done saving, let PrintDialogGtk::PrintDocument() continue.
  save_document_event_->Signal();

  if (error) {
    // Matches AddRef() in PrintDocument();
    Release();
  } else {
    // No errors, continue printing.
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(this,
                          &PrintDialogGtk::SendDocumentToPrinter,
                          document_name));
  }
}

void PrintDialogGtk::SendDocumentToPrinter(const string16& document_name) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If |printer_| is NULL then somehow the GTK printer list changed out under
  // us. In which case, just bail out.
  if (!printer_) {
    // Matches AddRef() in PrintDocument();
    Release();
    return;
  }

  GtkPrintJob* print_job = gtk_print_job_new(
      UTF16ToUTF8(document_name).c_str(),
      printer_,
      gtk_settings_,
      page_setup_);
  gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(), NULL);
  gtk_print_job_send(print_job, OnJobCompletedThunk, this, NULL);
}

// static
void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job,
                                         gpointer user_data,
                                         GError* error) {
  static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
}

void PrintDialogGtk::OnJobCompleted(GtkPrintJob* print_job, GError* error) {
  if (error)
    LOG(ERROR) << "Printing failed: " << error->message;
  if (print_job)
    g_object_unref(print_job);
  base::FileUtilProxy::Delete(
      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
      path_to_pdf_,
      false,
      NULL);
  // Printing finished. Matches AddRef() in PrintDocument();
  Release();
}

void PrintDialogGtk::InitPrintSettings(const PageRanges& page_ranges) {
  PrintSettings settings;
  printing::PrintSettingsInitializerGtk::InitPrintSettings(
      gtk_settings_, page_setup_, page_ranges, false, &settings);
  context_->InitWithSettings(settings);
}
<|endoftext|>


<commit_before><commit_msg>Disable sync. (Will be committed on beta branch only, and this CL will be immediately reverted.)<commit_after><|endoftext|>


<commit_before><commit_msg>Make sure the new frames' BrowserView2::TabSelectedAt calls TabContents::DidBecomeSelected, like Browser::TabSelectedAt does for the old frames. This was causing tab-restore related features (undo close tab, duplicate tab) to result in sad tab being shown when using the magic_browzR switch.<commit_after><|endoftext|>


<commit_before><commit_msg>Reverting 16802. Review URL: http://codereview.chromium.org/115726<commit_after><|endoftext|>


<commit_before><commit_msg>Fix new_tab_ui_cold_test for linux<commit_after><|endoftext|>


<commit_before><commit_msg>Fix crash_service to use different CommandLine API.<commit_after><|endoftext|>


<commit_before>#ifndef CLAMMBON_SORT_YRANGE2_HPP
#define CLAMMBON_SORT_YRANGE2_HPP

#include <vector>
#include <data_type.hpp>

class yrange2
{
private:
    typedef std::vector<std::vector<point_type>> return_type;

    question_raw_data const& data_;
    compared_type const& comp_;
    adjacent_type const adjacent_data_;

    // 2値座標系式から1値座標系式に変えながら和
    // 指定した範囲の配列の和を返す
    int array_sum(return_type const& array_, int const x, int const y, int const height, int const width) const;

	//縦入れ替え
	void yrange2::column_replacement(answer_type_y& answer);
	//横入れ替え
	void yrange2::row_replacement(answer_type_y& answer);
	//cv::Matの塊にする
	cv::Mat yrange2::combine_image(answer_type_y const& answer);

public:
    // 泣きのポインタ渡し
    yrange2(question_raw_data const& data, compared_type const& comp);
    virtual ~yrange2() = default;

    std::vector<std::vector<std::vector<point_type>>> operator() ();
};

#endif
<commit_msg>yrange2.hpp gcc対応<commit_after>#ifndef CLAMMBON_SORT_YRANGE2_HPP
#define CLAMMBON_SORT_YRANGE2_HPP

#include <vector>
#include <data_type.hpp>

class yrange2
{
private:
    typedef std::vector<std::vector<point_type>> return_type;

    question_raw_data const& data_;
    compared_type const& comp_;
    adjacent_type const adjacent_data_;

    // 2値座標系式から1値座標系式に変えながら和
    // 指定した範囲の配列の和を返す
    int array_sum(return_type const& array_, int const x, int const y, int const height, int const width) const;

	//縦入れ替え
	void column_replacement(answer_type_y& answer);
	//横入れ替え
	void row_replacement(answer_type_y& answer);
	//cv::Matの塊にする
	cv::Mat combine_image(answer_type_y const& answer);

public:
    // 泣きのポインタ渡し
    yrange2(question_raw_data const& data, compared_type const& comp);
    virtual ~yrange2() = default;

    std::vector<std::vector<std::vector<point_type>>> operator() ();
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GMBench.h"

GMBench::GMBench(skiagm::GM* gm) : fGM(gm) {
    fName.printf("GM_%s", gm->getName());
}

GMBench::~GMBench() { delete fGM; }

const char* GMBench::onGetName() {
    return fName.c_str();
}

bool GMBench::isSuitableFor(Backend backend) {
    return kNonRendering_Backend != backend;
}

void GMBench::onDraw(int loops, SkCanvas* canvas) {
    // Do we care about timing the draw of the background (once)?
    // Does the GM ever rely on drawBackground to lazily compute something?
    fGM->drawBackground(canvas);
    for (int i = 0; i < loops; ++i) {
        fGM->drawContent(canvas);
    }
}

SkIPoint GMBench::onGetSize() {
    SkISize size = fGM->getISize();
    return SkIPoint::Make(size.fWidth, size.fHeight);
}
<commit_msg>Run GM benchs in bench mode GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1978253002<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GMBench.h"

GMBench::GMBench(skiagm::GM* gm) : fGM(gm) {
    fName.printf("GM_%s", gm->getName());
}

GMBench::~GMBench() { delete fGM; }

const char* GMBench::onGetName() {
    return fName.c_str();
}

bool GMBench::isSuitableFor(Backend backend) {
    return kNonRendering_Backend != backend;
}

void GMBench::onDraw(int loops, SkCanvas* canvas) {
    fGM->setMode(skiagm::GM::kBench_Mode);
    // Do we care about timing the draw of the background (once)?
    // Does the GM ever rely on drawBackground to lazily compute something?
    fGM->drawBackground(canvas);
    for (int i = 0; i < loops; ++i) {
        fGM->drawContent(canvas);
    }
}

SkIPoint GMBench::onGetSize() {
    SkISize size = fGM->getISize();
    return SkIPoint::Make(size.fWidth, size.fHeight);
}
<|endoftext|>


<commit_before>#include <libmesh/elem.h>
#include <libmesh/mesh.h>
#include <libmesh/mesh_triangle_holes.h>
#include <libmesh/mesh_triangle_interface.h>
#include <libmesh/point.h>
#include <libmesh/poly2tri_triangulator.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

#include <cmath>

using namespace libMesh;

class MeshTriangulationTest : public CppUnit::TestCase
{
  /**
   * The goal of this test is to verify proper operation of the
   * interfaces to triangulation libraries
   */
public:
  CPPUNIT_TEST_SUITE( MeshTriangulationTest );

  CPPUNIT_TEST( testTriangleHoleArea );

#ifdef LIBMESH_HAVE_POLY2TRI
  CPPUNIT_TEST( testPoly2Tri );
#endif

#ifdef LIBMESH_HAVE_TRIANGLE
  CPPUNIT_TEST( testTriangle );
#endif

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  void testTriangleHoleArea()
  {
    // Using center=(1,0), radius=2 for the heck of it
    Point center{1};
    Real radius = 2;
    std::vector<TriangulatorInterface::PolygonHole> polyholes;

    // Line
    polyholes.emplace_back(center, radius, 2);
    // Triangle
    polyholes.emplace_back(center, radius, 3);
    // Square
    polyholes.emplace_back(center, radius, 4);
    // Pentagon
    polyholes.emplace_back(center, radius, 5);
    // Hexagon
    polyholes.emplace_back(center, radius, 6);

    for (int i=0; i != 5; ++i)
      {
        const int n_sides = i+2;
        const TriangulatorInterface::Hole & hole = polyholes[i];

        // Really?  This isn't until C++20?
        constexpr double my_pi = 3.141592653589793238462643383279;

        const Real computed_area = hole.area();
        const Real theta = my_pi/n_sides;
        const Real half_side_length = radius*std::cos(theta);
        const Real apothem = radius*std::sin(theta);
        const Real area = n_sides * apothem * half_side_length;

        LIBMESH_ASSERT_FP_EQUAL(computed_area, area, TOLERANCE*TOLERANCE);
      }

    TriangulatorInterface::ArbitraryHole arbhole {center, {{0,-1},{2,-1},{2,1},{0,2}}};
    LIBMESH_ASSERT_FP_EQUAL(arbhole.area(), Real(5), TOLERANCE*TOLERANCE);

#ifdef LIBMESH_HAVE_TRIANGLE
    // Make sure we're compatible with the old naming structure too
    TriangleInterface::PolygonHole square(center, radius, 4);
    LIBMESH_ASSERT_FP_EQUAL(square.area(), 2*radius*radius, TOLERANCE*TOLERANCE);
#endif
  }

  void testTriangulator(MeshBase & mesh,
                        TriangulatorInterface & triangulator)
  {
    // A non-square quad, so we don't have ambiguity about which
    // diagonal a Delaunay algorithm will pick.
    mesh.add_point(Point(0,0));
    mesh.add_point(Point(1,0));
    mesh.add_point(Point(1,2));
    mesh.add_point(Point(0,1));

    // Use the point order to define the boundary, because our
    // Poly2Tri implementation doesn't do convex hulls yet, even when
    // that would give the same answer.
    triangulator.triangulation_type() = TriangulatorInterface::PSLG;

    // Don't try to insert points yet
    triangulator.desired_area() = 1000;
    triangulator.minimum_angle() = 0;
    triangulator.smooth_after_generating() = false;

    triangulator.triangulate();

    CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), dof_id_type(2));
    for (const auto & elem : mesh.element_ptr_range())
      {
        CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);

        bool found_triangle = false;
        for (const auto & node : elem->node_ref_range())
          {
            const Point & point = node;
            if (point == Point(0,0))
              {
                found_triangle = true;
                CPPUNIT_ASSERT((elem->point(0) == Point(0,0) &&
                                elem->point(1) == Point(1,0) &&
                                elem->point(2) == Point(0,1)) ||
                               (elem->point(1) == Point(0,0) &&
                                elem->point(2) == Point(1,0) &&
                                elem->point(0) == Point(0,1)) ||
                               (elem->point(2) == Point(0,0) &&
                                elem->point(0) == Point(1,0) &&
                                elem->point(1) == Point(0,1)));
              }
            if (point == Point(1,2))
              {
                found_triangle = true;
                CPPUNIT_ASSERT((elem->point(0) == Point(0,1) &&
                                elem->point(1) == Point(1,0) &&
                                elem->point(2) == Point(1,2)) ||
                               (elem->point(1) == Point(0,1) &&
                                elem->point(2) == Point(1,0) &&
                                elem->point(0) == Point(1,2)) ||
                               (elem->point(2) == Point(0,1) &&
                                elem->point(0) == Point(1,0) &&
                                elem->point(1) == Point(1,2)));
              }
          }
        CPPUNIT_ASSERT(found_triangle);
      }
  }

  void testTriangle()
  {
#ifdef LIBMESH_HAVE_TRIANGLE
    Mesh mesh(*TestCommWorld);

    TriangleInterface triangle(mesh);

    testTriangulator(mesh, triangle);
#endif
  }

  void testPoly2Tri()
  {
#ifdef LIBMESH_HAVE_POLY2TRI
    Mesh mesh(*TestCommWorld);

    Poly2TriTriangulator p2t_tri(mesh);

    testTriangulator(mesh, p2t_tri);
#endif
  }

};

CPPUNIT_TEST_SUITE_REGISTRATION( MeshTriangulationTest );
<commit_msg>Unit tests for triangulating with a hole<commit_after>#include <libmesh/parallel_implementation.h> // max()
#include <libmesh/elem.h>
#include <libmesh/mesh.h>
#include <libmesh/mesh_triangle_holes.h>
#include <libmesh/mesh_triangle_interface.h>
#include <libmesh/point.h>
#include <libmesh/poly2tri_triangulator.h>

#include "test_comm.h"
#include "libmesh_cppunit.h"

#include <cmath>

using namespace libMesh;

class MeshTriangulationTest : public CppUnit::TestCase
{
  /**
   * The goal of this test is to verify proper operation of the
   * interfaces to triangulation libraries
   */
public:
  CPPUNIT_TEST_SUITE( MeshTriangulationTest );

  CPPUNIT_TEST( testTriangleHoleArea );

#ifdef LIBMESH_HAVE_POLY2TRI
  CPPUNIT_TEST( testPoly2Tri );
  CPPUNIT_TEST( testPoly2TriHoles );
#endif

#ifdef LIBMESH_HAVE_TRIANGLE
  CPPUNIT_TEST( testTriangle );
  CPPUNIT_TEST( testTriangleHoles );
#endif

  CPPUNIT_TEST_SUITE_END();

public:
  void setUp() {}

  void tearDown() {}

  void testTriangleHoleArea()
  {
    // Using center=(1,0), radius=2 for the heck of it
    Point center{1};
    Real radius = 2;
    std::vector<TriangulatorInterface::PolygonHole> polyholes;

    // Line
    polyholes.emplace_back(center, radius, 2);
    // Triangle
    polyholes.emplace_back(center, radius, 3);
    // Square
    polyholes.emplace_back(center, radius, 4);
    // Pentagon
    polyholes.emplace_back(center, radius, 5);
    // Hexagon
    polyholes.emplace_back(center, radius, 6);

    for (int i=0; i != 5; ++i)
      {
        const int n_sides = i+2;
        const TriangulatorInterface::Hole & hole = polyholes[i];

        // Really?  This isn't until C++20?
        constexpr double my_pi = 3.141592653589793238462643383279;

        const Real computed_area = hole.area();
        const Real theta = my_pi/n_sides;
        const Real half_side_length = radius*std::cos(theta);
        const Real apothem = radius*std::sin(theta);
        const Real area = n_sides * apothem * half_side_length;

        LIBMESH_ASSERT_FP_EQUAL(computed_area, area, TOLERANCE*TOLERANCE);
      }

    TriangulatorInterface::ArbitraryHole arbhole {center, {{0,-1},{2,-1},{2,1},{0,2}}};
    LIBMESH_ASSERT_FP_EQUAL(arbhole.area(), Real(5), TOLERANCE*TOLERANCE);

#ifdef LIBMESH_HAVE_TRIANGLE
    // Make sure we're compatible with the old naming structure too
    TriangleInterface::PolygonHole square(center, radius, 4);
    LIBMESH_ASSERT_FP_EQUAL(square.area(), 2*radius*radius, TOLERANCE*TOLERANCE);
#endif
  }

  void testTriangulator(MeshBase & mesh,
                        TriangulatorInterface & triangulator)
  {
    // A non-square quad, so we don't have ambiguity about which
    // diagonal a Delaunay algorithm will pick.
    mesh.add_point(Point(0,0));
    mesh.add_point(Point(1,0));
    mesh.add_point(Point(1,2));
    mesh.add_point(Point(0,1));

    // Use the point order to define the boundary, because our
    // Poly2Tri implementation doesn't do convex hulls yet, even when
    // that would give the same answer.
    triangulator.triangulation_type() = TriangulatorInterface::PSLG;

    // Don't try to insert points yet
    triangulator.desired_area() = 1000;
    triangulator.minimum_angle() = 0;
    triangulator.smooth_after_generating() = false;

    triangulator.triangulate();

    CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), dof_id_type(2));
    for (const auto & elem : mesh.element_ptr_range())
      {
        CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);

        bool found_triangle = false;
        for (const auto & node : elem->node_ref_range())
          {
            const Point & point = node;
            if (point == Point(0,0))
              {
                found_triangle = true;
                CPPUNIT_ASSERT((elem->point(0) == Point(0,0) &&
                                elem->point(1) == Point(1,0) &&
                                elem->point(2) == Point(0,1)) ||
                               (elem->point(1) == Point(0,0) &&
                                elem->point(2) == Point(1,0) &&
                                elem->point(0) == Point(0,1)) ||
                               (elem->point(2) == Point(0,0) &&
                                elem->point(0) == Point(1,0) &&
                                elem->point(1) == Point(0,1)));
              }
            if (point == Point(1,2))
              {
                found_triangle = true;
                CPPUNIT_ASSERT((elem->point(0) == Point(0,1) &&
                                elem->point(1) == Point(1,0) &&
                                elem->point(2) == Point(1,2)) ||
                               (elem->point(1) == Point(0,1) &&
                                elem->point(2) == Point(1,0) &&
                                elem->point(0) == Point(1,2)) ||
                               (elem->point(2) == Point(0,1) &&
                                elem->point(0) == Point(1,0) &&
                                elem->point(1) == Point(1,2)));
              }
          }
        CPPUNIT_ASSERT(found_triangle);
      }
  }

  void testTriangulatorHoles(MeshBase & mesh,
                             TriangulatorInterface & triangulator)
  {
    // A square quad; we'll put a diamond hole in the middle to make
    // the Delaunay selection unambiguous.
    mesh.add_point(Point(-1,-1));
    mesh.add_point(Point(1,-1));
    mesh.add_point(Point(1,1));
    mesh.add_point(Point(-1,1));

    // Use the point order to define the boundary, because our
    // Poly2Tri implementation doesn't do convex hulls yet, even when
    // that would give the same answer.
    triangulator.triangulation_type() = TriangulatorInterface::PSLG;

    // Add a diamond hole in the center
    TriangulatorInterface::PolygonHole diamond(Point(0), std::sqrt(2)/2, 4);
    const std::vector<TriangulatorInterface::Hole*> holes { &diamond };
    triangulator.attach_hole_list(&holes);

    // Don't try to insert points yet
    triangulator.desired_area() = 1000;
    triangulator.minimum_angle() = 0;
    triangulator.smooth_after_generating() = false;

    triangulator.triangulate();

    CPPUNIT_ASSERT_EQUAL(mesh.n_elem(), dof_id_type(8));

    Real r2p2o6 = (std::sqrt(Real(2))+2)/6;
    Real r2p4o6 = (std::sqrt(Real(2))+4)/6;

    std::vector <Point> expected_centers
    { {r2p2o6,r2p2o6}, {r2p2o6,-r2p2o6},
      {-r2p2o6,r2p2o6}, {-r2p2o6,-r2p2o6},
      {0,r2p4o6}, {r2p4o6, 0},
      {0,-r2p4o6}, {-r2p4o6, 0}
    };

    std::vector<bool> found_centers(expected_centers.size(), false);

    for (const auto & elem : mesh.element_ptr_range())
      {
        CPPUNIT_ASSERT_EQUAL(elem->type(), TRI3);

        Point center = elem->vertex_average();

        bool found_mine = false;
        for (auto i : index_range(expected_centers))
          {
            Point possible = expected_centers[i];

            if (possible.absolute_fuzzy_equals(center, TOLERANCE*TOLERANCE))
              {
                found_mine = true;
                found_centers[i] = true;
              }
          }
        CPPUNIT_ASSERT(found_mine);
      }

    mesh.comm().max(found_centers);

    for (auto found_it : found_centers)
      CPPUNIT_ASSERT(found_it);
  }

  void testTriangle()
  {
#ifdef LIBMESH_HAVE_TRIANGLE
    Mesh mesh(*TestCommWorld);
    TriangleInterface triangle(mesh);
    testTriangulator(mesh, triangle);
#endif
  }

  void testTriangleHoles()
  {
#ifdef LIBMESH_HAVE_TRIANGLE
    Mesh mesh(*TestCommWorld);
    TriangleInterface triangle(mesh);
    testTriangulatorHoles(mesh, triangle);
#endif
  }

  void testPoly2Tri()
  {
#ifdef LIBMESH_HAVE_POLY2TRI
    Mesh mesh(*TestCommWorld);
    Poly2TriTriangulator p2t_tri(mesh);
    testTriangulator(mesh, p2t_tri);
#endif
  }

  void testPoly2TriHoles()
  {
#ifdef LIBMESH_HAVE_POLY2TRI
    Mesh mesh(*TestCommWorld);
    Poly2TriTriangulator p2t_tri(mesh);
    testTriangulatorHoles(mesh, p2t_tri);
#endif
  }

};

CPPUNIT_TEST_SUITE_REGISTRATION( MeshTriangulationTest );
<|endoftext|>


<commit_before>#include <time.h>

#include <QtCore/QtPlugin>
#include <QtWidgets/QApplication>

#include "mainwindow/mainWindow.h"
#include "thirdparty/windowsmodernstyle.h"
#include <qrkernel/logging.h>
#include <qrutils/uxInfo/uxInfo.h>

#include "qrealApplication.h"

using namespace qReal;

int const maxLogSize = 10 * 1024 * 1024;  // 10 MB

void clearConfig()
{
	SettingsManager::clearSettings();
	SettingsManager::instance()->saveData();
}

void setDefaultLocale(bool localizationDisabled)
{
	if (localizationDisabled) {
		QLocale::setDefault(QLocale::English);
		return;
	}

	QString const locale = SettingsManager::value("systemLocale").toString();
	if (!locale.isEmpty()) {
		QLocale::setDefault(QLocale(locale));
	}
}

void initLogging()
{
	QDir const logsDir(QApplication::applicationDirPath() + "/logs");
	if (logsDir.mkpath(logsDir.absolutePath())) {
		Logger::addLogTarget(logsDir.filePath("qreal.log"), maxLogSize, 2);
		Logger::addLogTarget(logsDir.filePath("actions.log"), maxLogSize, 2, QsLogging::TraceLevel);
	}
}

int main(int argc, char *argv[])
{
	QDateTime const startedTime = QDateTime::currentDateTime();
	QRealApplication app(argc, argv);

	qsrand(time(0));
	setDefaultLocale(app.arguments().contains("--no-locale"));

	QTranslator guiTranslator;
	QTranslator utilsTranslator;
	QTranslator qtTranslator;
	guiTranslator.load(":/qrgui_" + QLocale().name());
	utilsTranslator.load(":/qrutils_" + QLocale().name());
	qtTranslator.load(":/qt_" + QLocale().name());
	app.installTranslator(&guiTranslator);
	app.installTranslator(&utilsTranslator);
	app.installTranslator(&qtTranslator);

	initLogging();
	QLOG_INFO() << "------------------- APPLICATION STARTED --------------------";
	QLOG_INFO() << "Setting default locale to" << QLocale().name();

	QString fileToOpen;
	if (app.arguments().count() > 1) {
		if (app.arguments().contains("--clear-conf")) {
			clearConfig();
			return 0;
		} else {
			int const setIndex = app.arguments().indexOf("--config");
			if (setIndex > -1) {
				QString const settingsFileName = app.arguments().at(setIndex + 1);
				SettingsManager::instance()->loadSettings(settingsFileName);
			}
			for (int i = 0; i < argc; i++) {
				if (app.arguments().at(i).endsWith(".qrs")) {
					fileToOpen = app.arguments().at(i);
					break;
				}
			}
		}
	}

#ifndef NO_STYLE_WINDOWSMODERN
	app.setStyle(new WindowsModernStyle());
#endif

	MainWindow window(fileToOpen);
	int exitCode = 0; // The window decided to not show itself, exiting now.

	if (window.isVisible()) {
		exitCode = app.exec();
	}

	QDateTime const currentTime = QDateTime::currentDateTime();
	QString const totalTime = QString::number(static_cast<qlonglong>(startedTime.secsTo(currentTime)));
	utils::UXInfo::reportTotalTime(totalTime, exitCode);
	QLOG_INFO() << "------------------- APPLICATION FINISHED -------------------";
	return exitCode;
}
<commit_msg>Added platform info logging<commit_after>#include <time.h>

#include <QtCore/QtPlugin>
#include <QtWidgets/QApplication>

#include "mainwindow/mainWindow.h"
#include "thirdparty/windowsmodernstyle.h"
#include <qrkernel/logging.h>
#include <qrutils/uxInfo/uxInfo.h>

#include "qrealApplication.h"

using namespace qReal;

int const maxLogSize = 10 * 1024 * 1024;  // 10 MB

void clearConfig()
{
	SettingsManager::clearSettings();
	SettingsManager::instance()->saveData();
}

void setDefaultLocale(bool localizationDisabled)
{
	if (localizationDisabled) {
		QLocale::setDefault(QLocale::English);
		return;
	}

	QString const locale = SettingsManager::value("systemLocale").toString();
	if (!locale.isEmpty()) {
		QLocale::setDefault(QLocale(locale));
	}
}

void initLogging()
{
	QDir const logsDir(QApplication::applicationDirPath() + "/logs");
	if (logsDir.mkpath(logsDir.absolutePath())) {
		Logger::addLogTarget(logsDir.filePath("qreal.log"), maxLogSize, 2);
		Logger::addLogTarget(logsDir.filePath("actions.log"), maxLogSize, 2, QsLogging::TraceLevel);
	}
}

QString platformInfo()
{
#if defined Q_OS_WIN32
	return QString("Windows ") + QSysInfo().windowsVersion()
#elif defined Q_OS_LINUX
	return "Linux";
#elif defined Q_OS_MAC
	return QString("Mac ") + QSysInfo().macVersion()
#endif
}

int main(int argc, char *argv[])
{
	QDateTime const startedTime = QDateTime::currentDateTime();
	QRealApplication app(argc, argv);

	qsrand(time(0));
	setDefaultLocale(app.arguments().contains("--no-locale"));

	QTranslator guiTranslator;
	QTranslator utilsTranslator;
	QTranslator qtTranslator;
	guiTranslator.load(":/qrgui_" + QLocale().name());
	utilsTranslator.load(":/qrutils_" + QLocale().name());
	qtTranslator.load(":/qt_" + QLocale().name());
	app.installTranslator(&guiTranslator);
	app.installTranslator(&utilsTranslator);
	app.installTranslator(&qtTranslator);

	initLogging();
	QLOG_INFO() << "------------------- APPLICATION STARTED --------------------";
	QLOG_INFO() << "Running on" << platformInfo();
	QLOG_INFO() << "Setting default locale to" << QLocale().name();

	QString fileToOpen;
	if (app.arguments().count() > 1) {
		if (app.arguments().contains("--clear-conf")) {
			clearConfig();
			return 0;
		} else {
			int const setIndex = app.arguments().indexOf("--config");
			if (setIndex > -1) {
				QString const settingsFileName = app.arguments().at(setIndex + 1);
				SettingsManager::instance()->loadSettings(settingsFileName);
			}
			for (int i = 0; i < argc; i++) {
				if (app.arguments().at(i).endsWith(".qrs")) {
					fileToOpen = app.arguments().at(i);
					break;
				}
			}
		}
	}

#ifndef NO_STYLE_WINDOWSMODERN
	app.setStyle(new WindowsModernStyle());
#endif

	MainWindow window(fileToOpen);
	int exitCode = 0; // The window decided to not show itself, exiting now.

	if (window.isVisible()) {
		exitCode = app.exec();
	}

	QDateTime const currentTime = QDateTime::currentDateTime();
	QString const totalTime = QString::number(static_cast<qlonglong>(startedTime.secsTo(currentTime)));
	utils::UXInfo::reportTotalTime(totalTime, exitCode);
	QLOG_INFO() << "------------------- APPLICATION FINISHED -------------------";
	return exitCode;
}
<|endoftext|>


<commit_before>#ifndef THIS_HASH_MAP
    #define THIS_HASH_MAP  parallel_flat_hash_map
    #define THIS_TEST_NAME ParallelFlatHashMap
#endif

#include "flat_hash_map_test.cc"

namespace phmap {
namespace priv {
namespace {

TEST(THIS_TEST_NAME, ThreadSafeContains) {
    // We can't test mutable keys, or non-copyable keys with ThisMap.
    // Test that the nodes have the proper API.
    using Map = ThisMap<int, int>;

    Map m = { {1, 7}, {2, 9} };
    const Map& const_m(m);

    auto val = 0;
    auto get_value = [&val](const int& v) { val = v; };
    EXPECT_TRUE(const_m.if_contains(2, get_value));
    EXPECT_EQ(val, 9);

    EXPECT_FALSE(m.if_contains(3, get_value));

    auto set_value = [](int& v) { v = 11; };
    EXPECT_TRUE(m.modify_if(2, set_value));
    EXPECT_EQ(m[2], 11);

    EXPECT_FALSE(m.modify_if(3, set_value)); // because m[3] does not exist

    // overwrite an existing value
    m.try_emplace_l(2, [](int& v) { v = 5; });
    EXPECT_EQ(m[2], 5);

    // insert a value that is not already present. Will be default initialised to 0 and lambda not called
    m.try_emplace_l(3,
                    [](int& v) { v = 6; }, // called only when key was already present
                    1);                    // argument to construct new value is key not present
    EXPECT_EQ(m[3], 1);

    // insert a value that is not already present, provide argument to value-construct it
    m.try_emplace_l(4,
                    [](int& ) {},          // called only when key was already present
                    999);                  // argument to construct new value is key not present
    EXPECT_EQ(m[4], 999);

    // insert a value that is not already present.
    // right now m[5] does not exist
    m.lazy_emplace_l(5,
                     [](int& v) { v = 6; },   // called only when key was already present
                     [](const Map::constructor& ctor) { ctor(5, 13); }); // construct value_type in place when key not present

    EXPECT_EQ(m[5], 13);

    // change a value that is present. Currently m[5] == 13
    m.lazy_emplace_l(5,
                     [](int& v) { v = 6; },   // called only when key was already present
                     [](const Map::constructor& ctor) { ctor(5, 13); }); // construct value_type in place when key not present
    EXPECT_EQ(m[5], 6);

    // test erase_if
    // -------------
    EXPECT_EQ(m.erase_if(4, [](int& v) { assert(0); return v==12; }), false); // m[4] not present - lambda not called
    EXPECT_EQ(m.erase_if(5, [](int& v) { return v==12; }), false);            // m[5] == 6, so erase not performed
    EXPECT_EQ(m[5], 6);
    EXPECT_EQ(m.erase_if(5, [](int& v) { return v==6; }), true);              // lambda returns true, so m[5] erased
    EXPECT_EQ(m[5], 0);

}

}  // namespace
}  // namespace priv
}  // namespace phmap
<commit_msg>Fix bug in test<commit_after>#ifndef THIS_HASH_MAP
    #define THIS_HASH_MAP  parallel_flat_hash_map
    #define THIS_TEST_NAME ParallelFlatHashMap
#endif

#include "flat_hash_map_test.cc"

namespace phmap {
namespace priv {
namespace {

TEST(THIS_TEST_NAME, ThreadSafeContains) {
    // We can't test mutable keys, or non-copyable keys with ThisMap.
    // Test that the nodes have the proper API.
    using Map = ThisMap<int, int>;

    Map m = { {1, 7}, {2, 9} };
    const Map& const_m(m);

    auto val = 0;
    auto get_value = [&val](const int& v) { val = v; };
    EXPECT_TRUE(const_m.if_contains(2, get_value));
    EXPECT_EQ(val, 9);

    EXPECT_FALSE(m.if_contains(3, get_value));

    auto set_value = [](int& v) { v = 11; };
    EXPECT_TRUE(m.modify_if(2, set_value));
    EXPECT_EQ(m[2], 11);

    EXPECT_FALSE(m.modify_if(3, set_value)); // because m[3] does not exist

    // overwrite an existing value
    m.try_emplace_l(2, [](int& v) { v = 5; });
    EXPECT_EQ(m[2], 5);

    // insert a value that is not already present. Will be default initialised to 0 and lambda not called
    m.try_emplace_l(3,
                    [](int& v) { v = 6; }, // called only when key was already present
                    1);                    // argument to construct new value is key not present
    EXPECT_EQ(m[3], 1);

    // insert a value that is not already present, provide argument to value-construct it
    m.try_emplace_l(4,
                    [](int& ) {},          // called only when key was already present
                    999);                  // argument to construct new value is key not present
    EXPECT_EQ(m[4], 999);

    // insert a value that is not already present.
    // right now m[5] does not exist
    m.lazy_emplace_l(5,
                     [](int& v) { v = 6; },   // called only when key was already present
                     [](const Map::constructor& ctor) { ctor(5, 13); }); // construct value_type in place when key not present

    EXPECT_EQ(m[5], 13);

    // change a value that is present. Currently m[5] == 13
    m.lazy_emplace_l(5,
                     [](int& v) { v = 6; },   // called only when key was already present
                     [](const Map::constructor& ctor) { ctor(5, 13); }); // construct value_type in place when key not present
    EXPECT_EQ(m[5], 6);

    // test erase_if
    // -------------
    EXPECT_EQ(m.erase_if(9, [](int& v) { assert(0); return v==12; }), false); // m[9] not present - lambda not called
    EXPECT_EQ(m.erase_if(5, [](int& v) { return v==12; }), false);            // m[5] == 6, so erase not performed
    EXPECT_EQ(m[5], 6);
    EXPECT_EQ(m.erase_if(5, [](int& v) { return v==6; }), true);              // lambda returns true, so m[5] erased
    EXPECT_EQ(m[5], 0);

}

}  // namespace
}  // namespace priv
}  // namespace phmap
<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "OrfDecoder.h"
#include "TiffParserOlympus.h"
#if defined(__unix__) || defined(__APPLE__)
#include <stdlib.h>
#endif
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

OrfDecoder::OrfDecoder(TiffIFD *rootIFD, FileMap* file):
    RawDecoder(file), mRootIFD(rootIFD) {
}

OrfDecoder::~OrfDecoder(void) {
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage OrfDecoder::decodeRawInternal() {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);

  if (data.empty())
    ThrowRDE("ORF Decoder: No image data found");

  TiffIFD* raw = data[0];

  int compression = raw->getEntry(COMPRESSION)->getInt();
  if (1 != compression)
    ThrowRDE("ORF Decoder: Unsupported compression");

  TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

  if (offsets->count != 1) {
    ThrowRDE("ORF Decoder: Multiple Strips found: %u", offsets->count);
  }
  if (counts->count != offsets->count) {
    ThrowRDE("ORF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count);
  }
  uint32 width = raw->getEntry(IMAGEWIDTH)->getInt();
  uint32 height = raw->getEntry(IMAGELENGTH)->getInt();

  if (!mFile->isValid(offsets->getInt() + counts->getInt()))
    ThrowRDE("ORF Decoder: Truncated file");

  mRaw->dim = iPoint2D(width, height);
  mRaw->createData();

  data = mRootIFD->getIFDsWithTag(MAKERNOTE);
  if (data.empty())
    ThrowRDE("ORF Decoder: No Makernote found");

  TiffIFD* exif = data[0];
  TiffEntry *makernoteEntry = exif->getEntry(MAKERNOTE);
  const uchar8* makernote = makernoteEntry->getData();
  FileMap makermap((uchar8*)&makernote[8], makernoteEntry->count - 8);
  try {
    TiffParserOlympus makertiff(&makermap);
    makertiff.parseData();
    data = makertiff.RootIFD()->getIFDsWithTag((TiffTag)0x2010);
    if (data.empty())
      ThrowRDE("ORF Decoder: Unsupported compression");
    TiffEntry *oly = data[0]->getEntry((TiffTag)0x2010);
    if (oly->type == TIFF_UNDEFINED)
      ThrowRDE("ORF Decoder: Unsupported compression");
  } catch (TiffParserException) {
    ThrowRDE("ORF Decoder: Unable to parse makernote");
  }

  // We add 3 bytes slack, since the bitpump might be a few bytes ahead.
  ByteStream s(mFile->getData(offsets->getInt()), counts->getInt() + 3);

  try {
    decodeCompressed(s, width, height);
  } catch (IOException e) {
    errors.push_back(_strdup(e.what()));
    // Let's ignore it, it may have delivered somewhat useful data.
  }

  return mRaw;
}
/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OrfDecoder::decodeCompressed(ByteStream& s, uint32 w, uint32 h) {
  int nbits, sign, low, high, i, left0, up, nw0, left1, nw1;
  int acarry0[3], acarry1[3], pred, diff;

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  char bittable[4096];
  for (i = 0; i < 4096; i++) {
    int b = i;
    for (high = 0; high < 12; high++)
      if ((b>>(11-high))&1)
        break;
      bittable[i] = high;
  }
  left0 = nw0 = left1 = nw1 = 0;

  s.skipBytes(7);
  BitPumpMSB bits(&s);

  for (uint32 y = 0; y < h; y++) {
    memset(acarry0, 0, sizeof acarry0);
    memset(acarry1, 0, sizeof acarry1);
    ushort16* dest = (ushort16*) & data[y*pitch];
    bool y_border = y < 2;
    bool border = TRUE;
    for (uint32 x = 0; x < w; x++) {
      bits.checkPos();
      bits.fill();
      i = 2 * (acarry0[2] < 3);
      for (nbits = 2 + i; (ushort16) acarry0[0] >> (nbits + i); nbits++);

      int b = bits.peekBitsNoFill(15);
      sign = (b >> 14) * -1;
      low  = (b >> 12) & 3;
      high = bittable[b&4095];
      // Skip bits used above.
      bits.skipBitsNoFill(min(12+3, high + 1 + 3));

      if (high == 12)
        high = bits.getBits(16 - nbits) >> 1;

      acarry0[0] = (high << nbits) | bits.getBits(nbits);
      diff = (acarry0[0] ^ sign) + acarry0[1];
      acarry0[1] = (diff * 3 + acarry0[1]) >> 5;
      acarry0[2] = acarry0[0] > 16 ? 0 : acarry0[2] + 1;

      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else if (y_border)
          pred = left0;
        else {
          pred = dest[-pitch+((int)x)];
          nw0 = pred;
        }
        dest[x] = pred + ((diff << 2) | low);
        // Set predictor
        left0 = dest[x];
      } else {
        up  = dest[-pitch+((int)x)];
        int leftMinusNw = left0 - nw0;
        int upMinusNw = up - nw0;
        // Check if sign is different, and one is not zero
        if (leftMinusNw * upMinusNw < 0) {
          if (other_abs(leftMinusNw) > 32 || other_abs(upMinusNw) > 32)
            pred = left0 + upMinusNw;
          else
            pred = (left0 + up) >> 1;
        } else
          pred = other_abs(leftMinusNw) > other_abs(upMinusNw) ? left0 : up;

        dest[x] = pred + ((diff << 2) | low);
        // Set predictors
        left0 = dest[x];
        nw0 = up;
      }

      // ODD PIXELS
      x += 1;
      bits.checkPos();
      bits.fill();
      i = 2 * (acarry1[2] < 3);
      for (nbits = 2 + i; (ushort16) acarry1[0] >> (nbits + i); nbits++);
      b = bits.peekBitsNoFill(15);
      sign = (b >> 14) * -1;
      low  = (b >> 12) & 3;
      high = bittable[b&4095];
      // Skip bits used above.
      bits.skipBitsNoFill(min(12+3, high + 1 + 3));

      if (high == 12)
        high = bits.getBits(16 - nbits) >> 1;

      acarry1[0] = (high << nbits) | bits.getBits(nbits);
      diff = (acarry1[0] ^ sign) + acarry1[1];
      acarry1[1] = (diff * 3 + acarry1[1]) >> 5;
      acarry1[2] = acarry1[0] > 16 ? 0 : acarry1[2] + 1;

      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else if (y_border)
          pred = left1;
        else {
          pred = dest[-pitch+((int)x)];
          nw1 = pred;
        }
        dest[x] = pred + ((diff << 2) | low);
        // Set predictor
        left1 = dest[x];
      } else {
        up  = dest[-pitch+((int)x)];
        int leftMinusNw = left1 - nw1;
        int upMinusNw = up - nw1;

        // Check if sign is different, and one is not zero
        if (leftMinusNw * upMinusNw < 0) {
          if (other_abs(leftMinusNw) > 32 || other_abs(upMinusNw) > 32)
            pred = left1 + upMinusNw;
          else
            pred = (left1 + up) >> 1;
        } else
          pred = other_abs(leftMinusNw) > other_abs(upMinusNw) ? left1 : up;

        dest[x] = pred + ((diff << 2) | low);

        // Set predictors
        left1 = dest[x];
        nw1 = up;
      }
	  border = y_border;
    }
  }
}

void OrfDecoder::checkSupport(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("ORF Support check: Model name found");
  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, "");
}

void OrfDecoder::decodeMetaData(CameraMetaData *meta) {
  int iso = 0;
  mRaw->cfa.setCFA(CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("ORF Meta Decoder: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();

  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt();

  setMetaData(meta, make, model, "", iso);

  TiffIFD *ImageProcessing = 0;
  try {
    data = mRootIFD->getIFDsWithTag(MAKERNOTE);

    if (!data.empty()) {
      TiffIFD* exif = data[0];
      TiffEntry *makernoteEntry = exif->getEntry(MAKERNOTE);
      const uchar8* makernote = makernoteEntry->getData();
      FileMap makermap((uchar8*)&makernote[8], makernoteEntry->count - 8);
      TiffParserOlympus makertiff(&makermap);
      makertiff.parseData();
      TiffEntry *blackEntry = 0;

      // Try reading black level from tag 0x2040 (Olympus Imageprocessing)
      if (makertiff.RootIFD()->hasEntryRecursive((TiffTag)0x2040)) {
        try {
          TiffEntry *imagep = makertiff.RootIFD()->getEntryRecursive((TiffTag)0x2040);

          int32 offset;
          const uchar8* data = imagep->getData();
          if (makertiff.tiff_endian = makertiff.getHostEndian())
            offset = *(int32*)data;
          else
            offset = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

          // It seems like Olympus doesn't mind data pointing out of the makernote,
          // so we give it the entire remaining file
          FileMap makermap2((uchar8*)&makernote[0], mFile->getSize()-makernoteEntry->getDataOffset());
          if (makertiff.getHostEndian() == makertiff.tiff_endian)
            ImageProcessing = new TiffIFD(&makermap2, offset);
          else
            ImageProcessing = new TiffIFDBE(&makermap2, offset);
          blackEntry = ImageProcessing->getEntry((TiffTag)0x600);
        } catch (TiffParserException) {
        }
      }

      // Otherwise try 0x1012
      if (!blackEntry && makertiff.RootIFD()->hasEntryRecursive((TiffTag)0x1012)) {
        blackEntry = makertiff.RootIFD()->getEntryRecursive((TiffTag)0x1012);
      }

      // Order is assumed to be RGGB
      if (blackEntry && blackEntry->count == 4) {
        const ushort16* black = blackEntry->getShortArray();
        for (int i = 0; i < 4; i++) {
          if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_RED)
            mRaw->blackLevelSeparate[i] = black[0];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_BLUE)
            mRaw->blackLevelSeparate[i] = black[3];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_GREEN && i<2)
            mRaw->blackLevelSeparate[i] = black[1];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_GREEN)
            mRaw->blackLevelSeparate[i] = black[2];
        }
        // Adjust whitelevel based on the read black (we assume the dynamic range is the same)
        mRaw->whitePoint -= (mRaw->blackLevel - mRaw->blackLevelSeparate[0]);
      }
    }
  } catch (TiffParserException) {
  }
  if (ImageProcessing)
    delete ImageProcessing;

}

} // namespace RawSpeed
<commit_msg>Fix host endianness detection in ORF.<commit_after>#include "StdAfx.h"
#include "OrfDecoder.h"
#include "TiffParserOlympus.h"
#if defined(__unix__) || defined(__APPLE__)
#include <stdlib.h>
#endif
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

OrfDecoder::OrfDecoder(TiffIFD *rootIFD, FileMap* file):
    RawDecoder(file), mRootIFD(rootIFD) {
}

OrfDecoder::~OrfDecoder(void) {
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage OrfDecoder::decodeRawInternal() {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);

  if (data.empty())
    ThrowRDE("ORF Decoder: No image data found");

  TiffIFD* raw = data[0];

  int compression = raw->getEntry(COMPRESSION)->getInt();
  if (1 != compression)
    ThrowRDE("ORF Decoder: Unsupported compression");

  TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

  if (offsets->count != 1) {
    ThrowRDE("ORF Decoder: Multiple Strips found: %u", offsets->count);
  }
  if (counts->count != offsets->count) {
    ThrowRDE("ORF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count);
  }
  uint32 width = raw->getEntry(IMAGEWIDTH)->getInt();
  uint32 height = raw->getEntry(IMAGELENGTH)->getInt();

  if (!mFile->isValid(offsets->getInt() + counts->getInt()))
    ThrowRDE("ORF Decoder: Truncated file");

  mRaw->dim = iPoint2D(width, height);
  mRaw->createData();

  data = mRootIFD->getIFDsWithTag(MAKERNOTE);
  if (data.empty())
    ThrowRDE("ORF Decoder: No Makernote found");

  TiffIFD* exif = data[0];
  TiffEntry *makernoteEntry = exif->getEntry(MAKERNOTE);
  const uchar8* makernote = makernoteEntry->getData();
  FileMap makermap((uchar8*)&makernote[8], makernoteEntry->count - 8);
  try {
    TiffParserOlympus makertiff(&makermap);
    makertiff.parseData();
    data = makertiff.RootIFD()->getIFDsWithTag((TiffTag)0x2010);
    if (data.empty())
      ThrowRDE("ORF Decoder: Unsupported compression");
    TiffEntry *oly = data[0]->getEntry((TiffTag)0x2010);
    if (oly->type == TIFF_UNDEFINED)
      ThrowRDE("ORF Decoder: Unsupported compression");
  } catch (TiffParserException) {
    ThrowRDE("ORF Decoder: Unable to parse makernote");
  }

  // We add 3 bytes slack, since the bitpump might be a few bytes ahead.
  ByteStream s(mFile->getData(offsets->getInt()), counts->getInt() + 3);

  try {
    decodeCompressed(s, width, height);
  } catch (IOException e) {
    errors.push_back(_strdup(e.what()));
    // Let's ignore it, it may have delivered somewhat useful data.
  }

  return mRaw;
}
/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OrfDecoder::decodeCompressed(ByteStream& s, uint32 w, uint32 h) {
  int nbits, sign, low, high, i, left0, up, nw0, left1, nw1;
  int acarry0[3], acarry1[3], pred, diff;

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  char bittable[4096];
  for (i = 0; i < 4096; i++) {
    int b = i;
    for (high = 0; high < 12; high++)
      if ((b>>(11-high))&1)
        break;
      bittable[i] = high;
  }
  left0 = nw0 = left1 = nw1 = 0;

  s.skipBytes(7);
  BitPumpMSB bits(&s);

  for (uint32 y = 0; y < h; y++) {
    memset(acarry0, 0, sizeof acarry0);
    memset(acarry1, 0, sizeof acarry1);
    ushort16* dest = (ushort16*) & data[y*pitch];
    bool y_border = y < 2;
    bool border = TRUE;
    for (uint32 x = 0; x < w; x++) {
      bits.checkPos();
      bits.fill();
      i = 2 * (acarry0[2] < 3);
      for (nbits = 2 + i; (ushort16) acarry0[0] >> (nbits + i); nbits++);

      int b = bits.peekBitsNoFill(15);
      sign = (b >> 14) * -1;
      low  = (b >> 12) & 3;
      high = bittable[b&4095];
      // Skip bits used above.
      bits.skipBitsNoFill(min(12+3, high + 1 + 3));

      if (high == 12)
        high = bits.getBits(16 - nbits) >> 1;

      acarry0[0] = (high << nbits) | bits.getBits(nbits);
      diff = (acarry0[0] ^ sign) + acarry0[1];
      acarry0[1] = (diff * 3 + acarry0[1]) >> 5;
      acarry0[2] = acarry0[0] > 16 ? 0 : acarry0[2] + 1;

      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else if (y_border)
          pred = left0;
        else {
          pred = dest[-pitch+((int)x)];
          nw0 = pred;
        }
        dest[x] = pred + ((diff << 2) | low);
        // Set predictor
        left0 = dest[x];
      } else {
        up  = dest[-pitch+((int)x)];
        int leftMinusNw = left0 - nw0;
        int upMinusNw = up - nw0;
        // Check if sign is different, and one is not zero
        if (leftMinusNw * upMinusNw < 0) {
          if (other_abs(leftMinusNw) > 32 || other_abs(upMinusNw) > 32)
            pred = left0 + upMinusNw;
          else
            pred = (left0 + up) >> 1;
        } else
          pred = other_abs(leftMinusNw) > other_abs(upMinusNw) ? left0 : up;

        dest[x] = pred + ((diff << 2) | low);
        // Set predictors
        left0 = dest[x];
        nw0 = up;
      }

      // ODD PIXELS
      x += 1;
      bits.checkPos();
      bits.fill();
      i = 2 * (acarry1[2] < 3);
      for (nbits = 2 + i; (ushort16) acarry1[0] >> (nbits + i); nbits++);
      b = bits.peekBitsNoFill(15);
      sign = (b >> 14) * -1;
      low  = (b >> 12) & 3;
      high = bittable[b&4095];
      // Skip bits used above.
      bits.skipBitsNoFill(min(12+3, high + 1 + 3));

      if (high == 12)
        high = bits.getBits(16 - nbits) >> 1;

      acarry1[0] = (high << nbits) | bits.getBits(nbits);
      diff = (acarry1[0] ^ sign) + acarry1[1];
      acarry1[1] = (diff * 3 + acarry1[1]) >> 5;
      acarry1[2] = acarry1[0] > 16 ? 0 : acarry1[2] + 1;

      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else if (y_border)
          pred = left1;
        else {
          pred = dest[-pitch+((int)x)];
          nw1 = pred;
        }
        dest[x] = pred + ((diff << 2) | low);
        // Set predictor
        left1 = dest[x];
      } else {
        up  = dest[-pitch+((int)x)];
        int leftMinusNw = left1 - nw1;
        int upMinusNw = up - nw1;

        // Check if sign is different, and one is not zero
        if (leftMinusNw * upMinusNw < 0) {
          if (other_abs(leftMinusNw) > 32 || other_abs(upMinusNw) > 32)
            pred = left1 + upMinusNw;
          else
            pred = (left1 + up) >> 1;
        } else
          pred = other_abs(leftMinusNw) > other_abs(upMinusNw) ? left1 : up;

        dest[x] = pred + ((diff << 2) | low);

        // Set predictors
        left1 = dest[x];
        nw1 = up;
      }
	  border = y_border;
    }
  }
}

void OrfDecoder::checkSupport(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("ORF Support check: Model name found");
  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, "");
}

void OrfDecoder::decodeMetaData(CameraMetaData *meta) {
  int iso = 0;
  mRaw->cfa.setCFA(CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("ORF Meta Decoder: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();

  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt();

  setMetaData(meta, make, model, "", iso);

  TiffIFD *ImageProcessing = 0;
  try {
    data = mRootIFD->getIFDsWithTag(MAKERNOTE);

    if (!data.empty()) {
      TiffIFD* exif = data[0];
      TiffEntry *makernoteEntry = exif->getEntry(MAKERNOTE);
      const uchar8* makernote = makernoteEntry->getData();
      FileMap makermap((uchar8*)&makernote[8], makernoteEntry->count - 8);
      TiffParserOlympus makertiff(&makermap);
      makertiff.parseData();
      TiffEntry *blackEntry = 0;

      // Try reading black level from tag 0x2040 (Olympus Imageprocessing)
      if (makertiff.RootIFD()->hasEntryRecursive((TiffTag)0x2040)) {
        try {
          TiffEntry *imagep = makertiff.RootIFD()->getEntryRecursive((TiffTag)0x2040);

          int32 offset;
          const uchar8* data = imagep->getData();
          if (makertiff.tiff_endian == makertiff.getHostEndian())
            offset = *(int32*)data;
          else
            offset = (unsigned int)data[0] << 24 | (unsigned int)data[1] << 16 | (unsigned int)data[2] << 8 | (unsigned int)data[3];

          // It seems like Olympus doesn't mind data pointing out of the makernote,
          // so we give it the entire remaining file
          FileMap makermap2((uchar8*)&makernote[0], mFile->getSize()-makernoteEntry->getDataOffset());
          if (makertiff.getHostEndian() == makertiff.tiff_endian)
            ImageProcessing = new TiffIFD(&makermap2, offset);
          else
            ImageProcessing = new TiffIFDBE(&makermap2, offset);
          blackEntry = ImageProcessing->getEntry((TiffTag)0x600);
        } catch (TiffParserException) {
        }
      }

      // Otherwise try 0x1012
      if (!blackEntry && makertiff.RootIFD()->hasEntryRecursive((TiffTag)0x1012)) {
        blackEntry = makertiff.RootIFD()->getEntryRecursive((TiffTag)0x1012);
      }

      // Order is assumed to be RGGB
      if (blackEntry && blackEntry->count == 4) {
        const ushort16* black = blackEntry->getShortArray();
        for (int i = 0; i < 4; i++) {
          if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_RED)
            mRaw->blackLevelSeparate[i] = black[0];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_BLUE)
            mRaw->blackLevelSeparate[i] = black[3];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_GREEN && i<2)
            mRaw->blackLevelSeparate[i] = black[1];
          else if (mRaw->cfa.getColorAt(i&1, i>>1) == CFA_GREEN)
            mRaw->blackLevelSeparate[i] = black[2];
        }
        // Adjust whitelevel based on the read black (we assume the dynamic range is the same)
        mRaw->whitePoint -= (mRaw->blackLevel - mRaw->blackLevelSeparate[0]);
      }
    }
  } catch (TiffParserException) {
  }
  if (ImageProcessing)
    delete ImageProcessing;

}

} // namespace RawSpeed
<|endoftext|>


<commit_before>
#include "QtApp.hpp"
#include "QtMenu.hpp"
#include "PythonHelpers.h"
#include "PyThreading.hpp"
#include <QAction>

// Dummy vars for QApplication.
// Note that the App construction is late at init. The Python code
// has already parsed all args and warned about unknown ones, etc.
// If we want to allow some Qt args, we should add some Python arg
// like "--qtargs" and pass those here.
static int dummy_argc = 1;
static char* dummy_argv[] = {(char*)"musicplayer", NULL};

QtApp::QtApp() : QApplication(dummy_argc, dummy_argv) {
	{
		QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(boost::function<void(void)>)");
		int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
		assert(methodIndex >= 0);
		genericExec_method = this->metaObject()->method(methodIndex);
	}

	this->setOrganizationName("Albert Zeyer");
	this->setApplicationName("MusicPlayer");

	connect(this, SIGNAL(aboutToQuit()), this, SLOT(handleApplicationQuit()));
}

void QtApp::handleApplicationQuit() {
	PyScopedGIL gil;

	printf("about to quit ...\n");

	PyObject* guiMod = getModule("gui"); // borrowed
	if(!guiMod) {
		printf("QtApp::handleApplicationQuit: gui module not found");
		return;
	}

	PyObject* ret = PyObject_CallMethod(guiMod, (char*)"handleApplicationQuit", NULL);
	if(!ret && PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(ret);
}

void QtApp::openWindowViaMenu() {
	if(sender() == NULL) {
		printf("QtApp::openWindowViaMenu: no sender\n");
		return;
	}

	QAction* act = qobject_cast<QAction*>(sender());
	if(!act) {
		printf("QtApp::openWindowViaMenu: sender is not QAction\n");
		return;
	}
	if(act->objectName().isEmpty()) {
		printf("QtApp::openWindowViaMenu: sender name is empty\n");
		return;
	}

	openWindow(act->objectName().toStdString());
}

void QtApp::openMainWindow() {
	openWindow("Main");
}

void QtApp::openWindow(const std::string& name) {

}

void QtApp::minimizeWindow() {
	QWidget* win = qApp->activeWindow();
	if(win) win->showMinimized();
}

void QtApp::closeWindow() {
	QWidget* win = qApp->activeWindow();
	if(win) win->close();
}

void QtApp::edit_cut() {
	QWidget* w = QApplication::focusWidget();
	//...
}

void QtApp::edit_copy() {

}

void QtApp::edit_paste() {

}

void QtApp::edit_selectAll() {

}

void QtApp::handlePlayerUpdate() {
	updateControlMenu();
}

void QtApp::playPause() {
	PyScopedGIL gil;
	PyObject* mod = getModule("State"); // borrowed
	if(!mod) return;

	PyObject* player = NULL;
	PyObject* playing = NULL;
	bool playingBool = false;

	player = attrChain(mod, "state.player");
	if(!player) goto final;

	playing = PyObject_GetAttrString(player, "playing");
	if(!playing) goto final;

	switch(PyObject_IsTrue(playing)) {
	case 1: playingBool = true; break;
	case 0: playingBool = false; break;
	default: goto final;
	}

	playingBool = !playingBool;
	PyObject_SetAttrString_retain(player, "playing", PyBool_FromLong(playingBool));

final:
	if(PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(player);
	Py_XDECREF(playing);
}

void QtApp::nextSong() {
	PyScopedGIL gil;
	PyObject* mod = getModule("State"); // borrowed
	if(!mod) return;

	PyObject* player = NULL;
	PyObject* ret = NULL;

	player = attrChain(mod, "state.player");
	ret = PyObject_CallMethod(player, "nextSong", NULL);

final:
	if(PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(player);
	Py_XDECREF(ret);
}

void QtApp::debug_resetPlayer() {

}
<commit_msg>dummy<commit_after>
#include "QtApp.hpp"
#include "QtMenu.hpp"
#include "PythonHelpers.h"
#include "PyThreading.hpp"
#include <QAction>

// Dummy vars for QApplication.
// Note that the App construction is late at init. The Python code
// has already parsed all args and warned about unknown ones, etc.
// If we want to allow some Qt args, we should add some Python arg
// like "--qtargs" and pass those here.
static int dummy_argc = 1;
static char* dummy_argv[] = {(char*)"musicplayer", NULL};

QtApp::QtApp() : QApplication(dummy_argc, dummy_argv) {
	{
		QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(boost::function<void(void)>)");
		int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
		assert(methodIndex >= 0);
		genericExec_method = this->metaObject()->method(methodIndex);
	}

	this->setOrganizationName("Albert Zeyer");
	this->setApplicationName("MusicPlayer");

	connect(this, SIGNAL(aboutToQuit()), this, SLOT(handleApplicationQuit()));
}

void QtApp::handleApplicationQuit() {
	PyScopedGIL gil;

	printf("about to quit ...\n");

	PyObject* guiMod = getModule("gui"); // borrowed
	if(!guiMod) {
		printf("QtApp::handleApplicationQuit: gui module not found");
		return;
	}

	PyObject* ret = PyObject_CallMethod(guiMod, (char*)"handleApplicationQuit", NULL);
	if(!ret && PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(ret);
}

void QtApp::openWindowViaMenu() {
	if(sender() == NULL) {
		printf("QtApp::openWindowViaMenu: no sender\n");
		return;
	}

	QAction* act = qobject_cast<QAction*>(sender());
	if(!act) {
		printf("QtApp::openWindowViaMenu: sender is not QAction\n");
		return;
	}
	if(act->objectName().isEmpty()) {
		printf("QtApp::openWindowViaMenu: sender name is empty\n");
		return;
	}

	openWindow(act->objectName().toStdString());
}

void QtApp::openMainWindow() {
	openWindow("Main");
}

void QtApp::openWindow(const std::string& name) {
	QWidget* win = new QWidget();
	win->setWindowTitle(name);
	// ...
}

void QtApp::minimizeWindow() {
	QWidget* win = qApp->activeWindow();
	if(win) win->showMinimized();
}

void QtApp::closeWindow() {
	QWidget* win = qApp->activeWindow();
	if(win) win->close();
}

void QtApp::edit_cut() {
	QWidget* w = QApplication::focusWidget();
	//...
}

void QtApp::edit_copy() {

}

void QtApp::edit_paste() {

}

void QtApp::edit_selectAll() {

}

void QtApp::handlePlayerUpdate() {
	updateControlMenu();
}

void QtApp::playPause() {
	PyScopedGIL gil;
	PyObject* mod = getModule("State"); // borrowed
	if(!mod) return;

	PyObject* player = NULL;
	PyObject* playing = NULL;
	bool playingBool = false;

	player = attrChain(mod, "state.player");
	if(!player) goto final;

	playing = PyObject_GetAttrString(player, "playing");
	if(!playing) goto final;

	switch(PyObject_IsTrue(playing)) {
	case 1: playingBool = true; break;
	case 0: playingBool = false; break;
	default: goto final;
	}

	playingBool = !playingBool;
	PyObject_SetAttrString_retain(player, "playing", PyBool_FromLong(playingBool));

final:
	if(PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(player);
	Py_XDECREF(playing);
}

void QtApp::nextSong() {
	PyScopedGIL gil;
	PyObject* mod = getModule("State"); // borrowed
	if(!mod) return;

	PyObject* player = NULL;
	PyObject* ret = NULL;

	player = attrChain(mod, "state.player");
	ret = PyObject_CallMethod(player, "nextSong", NULL);

final:
	if(PyErr_Occurred()) PyErr_Print();
	Py_XDECREF(player);
	Py_XDECREF(ret);
}

void QtApp::debug_resetPlayer() {

}
<|endoftext|>