<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 <windows.h>

#include "base/basictypes.h"

#include "WTF/ListHashSet.h"
#include "WTF/Vector.h"

#include "SkiaFontWin.h"

#include "SkCanvas.h"
#include "SkPaint.h"

namespace WebCore {

namespace {

struct CachedOutlineKey {
    CachedOutlineKey() : font(NULL), glyph(0), path(NULL) {}
    CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(NULL) {}

    HFONT font;
    WORD glyph;

    // The lifetime of this pointer is managed externally to this class. Be sure
    // to call DeleteOutline to remove items.
    SkPath* path;
};

const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b)
{
    return a.font == b.font && a.glyph == b.glyph;
}

struct CachedOutlineKeyHash {
    static unsigned hash(const CachedOutlineKey& key)
    {
        return bit_cast<unsigned>(key.font) + key.glyph;
    }

    static unsigned equal(const CachedOutlineKey& a,
                          const CachedOutlineKey& b)
    {
        return a.font == b.font && a.glyph == b.glyph;
    }

    static const bool safeToCompareToEmptyOrDeleted = true;
};

typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache;
OutlineCache outlineCache;

// The global number of glyph outlines we'll cache.
const int outlineCacheSize = 256;

inline FIXED SkScalarToFIXED(SkScalar x)
{
    return bit_cast<FIXED>(SkScalarToFixed(x));
}

inline SkScalar FIXEDToSkScalar(FIXED fixed)
{
    return SkFixedToScalar(bit_cast<SkFixed>(fixed));
}

// Removes the given key from the cached outlines, also deleting the path.
void DeleteOutline(OutlineCache::iterator deleteMe)
{
    delete deleteMe->path;
    outlineCache.remove(deleteMe);
}

void AddPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path)
{
    switch (polyCurve->wType) {
    case TT_PRIM_LINE:
        for (WORD i = 0; i < polyCurve->cpfx; i++) {
          path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x),
                       -FIXEDToSkScalar(polyCurve->apfx[i].y));
        }
        break;

    case TT_PRIM_QSPLINE:
        // FIXME(brettw) doesn't this duplicate points if we do the loop > once?
        for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {
            SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);
            SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);

            SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);
            SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);
            if (i < polyCurve->cpfx - 2) {
                // We're not the last point, compute C.
                cx = SkScalarAve(bx, cx);
                cy = SkScalarAve(by, cy);
            }

            // Need to flip the y coordinates since the font's coordinate system is
            // flipped from ours vertically.
            path->quadTo(bx, -by, cx, -cy);
        }
        break;

    case TT_PRIM_CSPLINE:
        // FIXME
        break;
    }
}

// Fills the given SkPath with the outline for the given glyph index. The font
// currently selected into the given DC is used. Returns true on success.
bool GetPathForGlyph(HDC dc, WORD glyph, SkPath* path)
{
    char buffer[4096];
    GLYPHMETRICS gm;
    MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};  // Each one is (fract,value).

    DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,
                                     &gm, arraysize(buffer), buffer, &mat);
    if (totalSize == GDI_ERROR)
        return false;

    const char* curGlyph = buffer;
    const char* endGlyph = &buffer[totalSize];
    while (curGlyph < endGlyph) {
        const TTPOLYGONHEADER* polyHeader =
            reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);
        path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),
                     -FIXEDToSkScalar(polyHeader->pfxStart.y));

        const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);
        const char* endPoly = curGlyph + polyHeader->cb;
        while (curPoly < endPoly) {
            const TTPOLYCURVE* polyCurve =
                reinterpret_cast<const TTPOLYCURVE*>(curPoly);
            AddPolyCurveToPath(polyCurve, path);
            curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
        }
        curGlyph += polyHeader->cb;
    }

    path->close();
    return true;
}

// Returns a SkPath corresponding to the give glyph in the given font. The font
// should be selected into the given DC. The returned path is owned by the
// hashtable. Returns NULL on error.
const SkPath* GetCachedPathForGlyph(HDC hdc, HFONT font, WORD glyph)
{
    CachedOutlineKey key(font, glyph);
    OutlineCache::iterator found = outlineCache.find(key);
    if (found != outlineCache.end()) {
        // Keep in MRU order by removing & reinserting the value.
        key = *found;
        outlineCache.remove(found);
        outlineCache.add(key);
        return key.path;
    }

    key.path = new SkPath;
    if (!GetPathForGlyph(hdc, glyph, key.path))
      return NULL;

    if (outlineCache.size() > outlineCacheSize) {
        // The cache is too big, find the oldest value (first in the list).
        DeleteOutline(outlineCache.begin());
    }

    outlineCache.add(key);
    return key.path;
}

}  // namespace

bool SkiaDrawText(HFONT hfont,
                  SkCanvas* canvas,
                  const SkPoint& point,
                  SkPaint* paint,
                  const WORD* glyphs,
                  const int* advances,
                  int num_glyphs)
{
    HDC dc = GetDC(0);
    HGDIOBJ old_font = SelectObject(dc, hfont);

    canvas->save();
    canvas->translate(point.fX, point.fY);

    for (int i = 0; i < num_glyphs; i++) {
        const SkPath* path = GetCachedPathForGlyph(dc, hfont, glyphs[i]);
        if (!path)
            return false;
        canvas->drawPath(*path, *paint);
        canvas->translate(advances[i], 0);
    }

    canvas->restore();

    SelectObject(dc, old_font);
    ReleaseDC(0, dc);
    return true;
}

/* TODO(brettw) finish this implementation
bool SkiaDrawComplexText(HFONT font,
                         SkCanvas* canvas,
                         const SkPoint& point,
                         SkPaint* paint
                         UINT fuOptions,
                         const SCRIPT_ANALYSIS* psa,
                         const WORD* pwGlyphs,
                         int cGlyphs,
                         const int* advances,
                         const int* justifies,
                         const GOFFSET* glyph_offsets)
{
    HDC dc = GetDC(0);
    HGDIOBJ old_font = SelectObject(dc, hfont);

    canvas->save();
    canvas->translate(point.fX, point.fY);

    for (int i = 0; i < cGlyphs; i++) {
        canvas->translate(glyph_offsets[i].du, glyph_offsets[i].dv);

        // Undo the offset for this glyph.
        canvas->translate(-glyph_offsets[i].du, -glyph_offsets[i].dv);

        // And advance to where we're drawing the next one. We use the justifies
        // run since that is the justified advances for each character, rather than
        // the adnvaces one.
        canvas->translate(justifies[i], 0);
    }

    canvas->restore();

    SelectObject(dc, old_font);
    ReleaseDC(0, dc);
}*/

void RemoveFontFromSkiaFontWinCache(HFONT hfont)
{
    // ListHashSet isn't the greatest structure for deleting stuff out of, but
    // removing entries will be relatively rare (we don't remove fonts much, nor
    // do we draw out own glyphs using these routines much either).
    //
    // We keep a list of all glyphs we're removing which we do in a separate
    // pass.
    Vector<CachedOutlineKey> outlinesToDelete;
    for (OutlineCache::iterator i = outlineCache.begin();
         i != outlineCache.end(); ++i)
        outlinesToDelete.append(*i);

    for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();
         i != outlinesToDelete.end(); ++i)
        DeleteOutline(outlineCache.find(*i));
}

}  // namespace WebCore
<commit_msg>De-basify SkiaFontwin<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 <windows.h>

#include "WTF/ListHashSet.h"
#include "WTF/Vector.h"

#include "SkiaFontWin.h"

#include "SkCanvas.h"
#include "SkPaint.h"

namespace WebCore {

namespace {

struct CachedOutlineKey {
    CachedOutlineKey() : font(NULL), glyph(0), path(NULL) {}
    CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(NULL) {}

    HFONT font;
    WORD glyph;

    // The lifetime of this pointer is managed externally to this class. Be sure
    // to call DeleteOutline to remove items.
    SkPath* path;
};

const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b)
{
    return a.font == b.font && a.glyph == b.glyph;
}

struct CachedOutlineKeyHash {
    static unsigned hash(const CachedOutlineKey& key)
    {
        unsigned keyBytes;
        memcpy(&keyBytes, &key.font, sizeof(unsigned));
        return keyBytes + key.glyph;
    }

    static unsigned equal(const CachedOutlineKey& a,
                          const CachedOutlineKey& b)
    {
        return a.font == b.font && a.glyph == b.glyph;
    }

    static const bool safeToCompareToEmptyOrDeleted = true;
};

typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache;
OutlineCache outlineCache;

// The global number of glyph outlines we'll cache.
const int outlineCacheSize = 256;

inline FIXED SkScalarToFIXED(SkScalar x)
{
    FIXED fixed;
    SkFixed skFixed = SkScalarToFixed(x);
    memcpy(&fixed, &skFixed, sizeof(FIXED));
    return fixed;
}

inline SkScalar FIXEDToSkScalar(FIXED fixed)
{
    SkFixed skFixed;
    memcpy(&skFixed, &fixed, sizeof(SkFixed));
    return SkFixedToScalar(skFixed);
}

// Removes the given key from the cached outlines, also deleting the path.
void DeleteOutline(OutlineCache::iterator deleteMe)
{
    delete deleteMe->path;
    outlineCache.remove(deleteMe);
}

void AddPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path)
{
    switch (polyCurve->wType) {
    case TT_PRIM_LINE:
        for (WORD i = 0; i < polyCurve->cpfx; i++) {
          path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x),
                       -FIXEDToSkScalar(polyCurve->apfx[i].y));
        }
        break;

    case TT_PRIM_QSPLINE:
        // FIXME(brettw) doesn't this duplicate points if we do the loop > once?
        for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {
            SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);
            SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);

            SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);
            SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);
            if (i < polyCurve->cpfx - 2) {
                // We're not the last point, compute C.
                cx = SkScalarAve(bx, cx);
                cy = SkScalarAve(by, cy);
            }

            // Need to flip the y coordinates since the font's coordinate system is
            // flipped from ours vertically.
            path->quadTo(bx, -by, cx, -cy);
        }
        break;

    case TT_PRIM_CSPLINE:
        // FIXME
        break;
    }
}

// The size of the glyph outline buffer.
const int glyphPathBufferSize = 4096;

// Fills the given SkPath with the outline for the given glyph index. The font
// currently selected into the given DC is used. Returns true on success.
bool GetPathForGlyph(HDC dc, WORD glyph, SkPath* path)
{
    char buffer[glyphPathBufferSize];
    GLYPHMETRICS gm;
    MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};  // Each one is (fract,value).

    DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,
                                       &gm, glyphPathBufferSize, buffer, &mat);
    if (totalSize == GDI_ERROR)
        return false;

    const char* curGlyph = buffer;
    const char* endGlyph = &buffer[totalSize];
    while (curGlyph < endGlyph) {
        const TTPOLYGONHEADER* polyHeader =
            reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);
        path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),
                     -FIXEDToSkScalar(polyHeader->pfxStart.y));

        const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);
        const char* endPoly = curGlyph + polyHeader->cb;
        while (curPoly < endPoly) {
            const TTPOLYCURVE* polyCurve =
                reinterpret_cast<const TTPOLYCURVE*>(curPoly);
            AddPolyCurveToPath(polyCurve, path);
            curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
        }
        curGlyph += polyHeader->cb;
    }

    path->close();
    return true;
}

// Returns a SkPath corresponding to the give glyph in the given font. The font
// should be selected into the given DC. The returned path is owned by the
// hashtable. Returns NULL on error.
const SkPath* GetCachedPathForGlyph(HDC hdc, HFONT font, WORD glyph)
{
    CachedOutlineKey key(font, glyph);
    OutlineCache::iterator found = outlineCache.find(key);
    if (found != outlineCache.end()) {
        // Keep in MRU order by removing & reinserting the value.
        key = *found;
        outlineCache.remove(found);
        outlineCache.add(key);
        return key.path;
    }

    key.path = new SkPath;
    if (!GetPathForGlyph(hdc, glyph, key.path))
      return NULL;

    if (outlineCache.size() > outlineCacheSize) {
        // The cache is too big, find the oldest value (first in the list).
        DeleteOutline(outlineCache.begin());
    }

    outlineCache.add(key);
    return key.path;
}

}  // namespace

bool SkiaDrawText(HFONT hfont,
                  SkCanvas* canvas,
                  const SkPoint& point,
                  SkPaint* paint,
                  const WORD* glyphs,
                  const int* advances,
                  int num_glyphs)
{
    HDC dc = GetDC(0);
    HGDIOBJ old_font = SelectObject(dc, hfont);

    canvas->save();
    canvas->translate(point.fX, point.fY);

    for (int i = 0; i < num_glyphs; i++) {
        const SkPath* path = GetCachedPathForGlyph(dc, hfont, glyphs[i]);
        if (!path)
            return false;
        canvas->drawPath(*path, *paint);
        canvas->translate(advances[i], 0);
    }

    canvas->restore();

    SelectObject(dc, old_font);
    ReleaseDC(0, dc);
    return true;
}

/* TODO(brettw) finish this implementation
bool SkiaDrawComplexText(HFONT font,
                         SkCanvas* canvas,
                         const SkPoint& point,
                         SkPaint* paint
                         UINT fuOptions,
                         const SCRIPT_ANALYSIS* psa,
                         const WORD* pwGlyphs,
                         int cGlyphs,
                         const int* advances,
                         const int* justifies,
                         const GOFFSET* glyph_offsets)
{
    HDC dc = GetDC(0);
    HGDIOBJ old_font = SelectObject(dc, hfont);

    canvas->save();
    canvas->translate(point.fX, point.fY);

    for (int i = 0; i < cGlyphs; i++) {
        canvas->translate(glyph_offsets[i].du, glyph_offsets[i].dv);

        // Undo the offset for this glyph.
        canvas->translate(-glyph_offsets[i].du, -glyph_offsets[i].dv);

        // And advance to where we're drawing the next one. We use the justifies
        // run since that is the justified advances for each character, rather than
        // the adnvaces one.
        canvas->translate(justifies[i], 0);
    }

    canvas->restore();

    SelectObject(dc, old_font);
    ReleaseDC(0, dc);
}*/

void RemoveFontFromSkiaFontWinCache(HFONT hfont)
{
    // ListHashSet isn't the greatest structure for deleting stuff out of, but
    // removing entries will be relatively rare (we don't remove fonts much, nor
    // do we draw out own glyphs using these routines much either).
    //
    // We keep a list of all glyphs we're removing which we do in a separate
    // pass.
    Vector<CachedOutlineKey> outlinesToDelete;
    for (OutlineCache::iterator i = outlineCache.begin();
         i != outlineCache.end(); ++i)
        outlinesToDelete.append(*i);

    for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();
         i != outlinesToDelete.end(); ++i)
        DeleteOutline(outlineCache.find(*i));
}

}  // namespace WebCore
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/ui/gtk/extensions/native_app_window_gtk.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/gtk_window_util.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/base/x/active_window_watcher_x.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"

namespace {

// The timeout in milliseconds before we'll get the true window position with
// gtk_window_get_position() after the last GTK configure-event signal.
const int kDebounceTimeoutMilliseconds = 100;

} // namespace

NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window,
                                       const ShellWindow::CreateParams& params)
    : shell_window_(shell_window),
      window_(NULL),
      state_(GDK_WINDOW_STATE_WITHDRAWN),
      is_active_(false),
      content_thinks_its_fullscreen_(false),
      frameless_(params.frame == ShellWindow::FRAME_NONE) {
  window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));

  gfx::NativeView native_view =
      web_contents()->GetView()->GetNativeView();
  gtk_container_add(GTK_CONTAINER(window_), native_view);

  if (params.bounds.x() != INT_MIN && params.bounds.y() != INT_MIN)
    gtk_window_move(window_, params.bounds.x(), params.bounds.y());

  // This is done to avoid a WM "feature" where setting the window size to
  // the monitor size causes the WM to set the EWMH for full screen mode.
  if (frameless_ &&
      gtk_window_util::BoundsMatchMonitorSize(window_, params.bounds)) {
    gtk_window_set_default_size(
        window_, params.bounds.width(), params.bounds.height() - 1);
  } else {
    gtk_window_set_default_size(
        window_, params.bounds.width(), params.bounds.height());
  }

  // make sure bounds_ and restored_bounds_ have correct values until we
  // get our first configure-event
  bounds_ = restored_bounds_ = params.bounds;
  gint x, y;
  gtk_window_get_position(window_, &x, &y);
  bounds_.set_origin(gfx::Point(x, y));

  // Hide titlebar when {frame: 'none'} specified on ShellWindow.
  if (frameless_)
    gtk_window_set_decorated(window_, false);

  int min_width = params.minimum_size.width();
  int min_height = params.minimum_size.height();
  int max_width = params.maximum_size.width();
  int max_height = params.maximum_size.height();
  GdkGeometry hints;
  int hints_mask = 0;
  if (min_width || min_height) {
    hints.min_height = min_height;
    hints.min_width = min_width;
    hints_mask |= GDK_HINT_MIN_SIZE;
  }
  if (max_width || max_height) {
    hints.max_height = max_height ? max_height : G_MAXINT;
    hints.max_width = max_width ? max_width : G_MAXINT;
    hints_mask |= GDK_HINT_MAX_SIZE;
  }
  if (hints_mask) {
    gtk_window_set_geometry_hints(
        window_,
        GTK_WIDGET(window_),
        &hints,
        static_cast<GdkWindowHints>(hints_mask));
  }

  // In some (older) versions of compiz, raising top-level windows when they
  // are partially off-screen causes them to get snapped back on screen, not
  // always even on the current virtual desktop.  If we are running under
  // compiz, suppress such raises, as they are not necessary in compiz anyway.
  if (ui::GuessWindowManager() == ui::WM_COMPIZ)
    suppress_window_raise_ = true;

  gtk_window_set_title(window_, extension()->name().c_str());

  gtk_window_util::SetWindowCustomClass(window_,
      web_app::GetWMClassFromAppName(extension()->name()));

  g_signal_connect(window_, "delete-event",
                   G_CALLBACK(OnMainWindowDeleteEventThunk), this);
  g_signal_connect(window_, "configure-event",
                   G_CALLBACK(OnConfigureThunk), this);
  g_signal_connect(window_, "window-state-event",
                   G_CALLBACK(OnWindowStateThunk), this);
  if (frameless_) {
    g_signal_connect(window_, "button-press-event",
                     G_CALLBACK(OnButtonPressThunk), this);
  }

  // Add the keybinding registry.
  extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk(
      shell_window_->profile(),
      window_,
      extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
      shell_window_));

  ui::ActiveWindowWatcherX::AddObserver(this);
}

NativeAppWindowGtk::~NativeAppWindowGtk() {
  ui::ActiveWindowWatcherX::RemoveObserver(this);
}

bool NativeAppWindowGtk::IsActive() const {
  if (ui::ActiveWindowWatcherX::WMSupportsActivation())
    return is_active_;

  // This still works even though we don't get the activation notification.
  return gtk_window_is_active(window_);
}

bool NativeAppWindowGtk::IsMaximized() const {
  return (state_ & GDK_WINDOW_STATE_MAXIMIZED);
}

bool NativeAppWindowGtk::IsMinimized() const {
  return (state_ & GDK_WINDOW_STATE_ICONIFIED);
}

bool NativeAppWindowGtk::IsFullscreen() const {
  return false;
}

gfx::NativeWindow NativeAppWindowGtk::GetNativeWindow() {
  return window_;
}

gfx::Rect NativeAppWindowGtk::GetRestoredBounds() const {
  return restored_bounds_;
}

gfx::Rect NativeAppWindowGtk::GetBounds() const {
  return bounds_;
}

void NativeAppWindowGtk::Show() {
  gtk_window_present(window_);
}

void NativeAppWindowGtk::ShowInactive() {
  gtk_window_set_focus_on_map(window_, false);
  gtk_widget_show(GTK_WIDGET(window_));
}

void NativeAppWindowGtk::Hide() {
  gtk_widget_hide(GTK_WIDGET(window_));
}

void NativeAppWindowGtk::Close() {
  shell_window_->OnNativeWindowChanged();

  // Cancel any pending callback from the window configure debounce timer.
  window_configure_debounce_timer_.Stop();

  GtkWidget* window = GTK_WIDGET(window_);
  // To help catch bugs in any event handlers that might get fired during the
  // destruction, set window_ to NULL before any handlers will run.
  window_ = NULL;

  // OnNativeClose does a delete this so no other members should
  // be accessed after. gtk_widget_destroy is safe (and must
  // be last).
  shell_window_->OnNativeClose();
  gtk_widget_destroy(window);
}

void NativeAppWindowGtk::Activate() {
  gtk_window_present(window_);
}

void NativeAppWindowGtk::Deactivate() {
  gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
}

void NativeAppWindowGtk::Maximize() {
  gtk_window_maximize(window_);
}

void NativeAppWindowGtk::Minimize() {
  gtk_window_iconify(window_);
}

void NativeAppWindowGtk::Restore() {
  if (IsMaximized())
    gtk_window_unmaximize(window_);
  else if (IsMinimized())
    gtk_window_deiconify(window_);
}

void NativeAppWindowGtk::SetBounds(const gfx::Rect& bounds) {
  gtk_window_move(window_, bounds.x(), bounds.y());
  gtk_window_util::SetWindowSize(window_,
      gfx::Size(bounds.width(), bounds.height()));
}

void NativeAppWindowGtk::FlashFrame(bool flash) {
  gtk_window_set_urgency_hint(window_, flash);
}

bool NativeAppWindowGtk::IsAlwaysOnTop() const {
  return false;
}

gfx::Insets NativeAppWindowGtk::GetFrameInsets() const {
  if (frameless_)
    return gfx::Insets();
  GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
  if (!gdk_window)
    return gfx::Insets();

  gint current_width = 0;
  gint current_height = 0;
  gtk_window_get_size(window_, &current_width, &current_height);
  gint current_x = 0;
  gint current_y = 0;
  gdk_window_get_position(gdk_window, &current_x, &current_y);
  GdkRectangle rect_with_decorations = {0};
  gdk_window_get_frame_extents(gdk_window,
                               &rect_with_decorations);

  int left_inset = current_x - rect_with_decorations.x;
  int top_inset = current_y - rect_with_decorations.y;
  return gfx::Insets(
      top_inset,
      left_inset,
      rect_with_decorations.height - current_height - top_inset,
      rect_with_decorations.width - current_width - left_inset);
}

void NativeAppWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
  // Do nothing if we're in the process of closing the browser window.
  if (!window_)
    return;

  is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
}

// Callback for the delete event.  This event is fired when the user tries to
// close the window (e.g., clicking on the X in the window manager title bar).
gboolean NativeAppWindowGtk::OnMainWindowDeleteEvent(GtkWidget* widget,
                                                     GdkEvent* event) {
  Close();

  // Return true to prevent the GTK window from being destroyed.  Close will
  // destroy it for us.
  return TRUE;
}

gboolean NativeAppWindowGtk::OnConfigure(GtkWidget* widget,
                                         GdkEventConfigure* event) {
  // We update |bounds_| but not |restored_bounds_| here.  The latter needs
  // to be updated conditionally when the window is non-maximized and non-
  // fullscreen, but whether those state updates have been processed yet is
  // window-manager specific.  We update |restored_bounds_| in the debounced
  // handler below, after the window state has been updated.
  bounds_.SetRect(event->x, event->y, event->width, event->height);

  // The GdkEventConfigure* we get here doesn't have quite the right
  // coordinates though (they're relative to the drawable window area, rather
  // than any window manager decorations, if enabled), so we need to call
  // gtk_window_get_position() to get the right values. (Otherwise session
  // restore, if enabled, will restore windows to incorrect positions.) That's
  // a round trip to the X server though, so we set a debounce timer and only
  // call it (in OnDebouncedBoundsChanged() below) after we haven't seen a
  // reconfigure event in a short while.
  // We don't use Reset() because the timer may not yet be running.
  // (In that case Stop() is a no-op.)
  window_configure_debounce_timer_.Stop();
  window_configure_debounce_timer_.Start(FROM_HERE,
      base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), this,
      &NativeAppWindowGtk::OnDebouncedBoundsChanged);

  return FALSE;
}

void NativeAppWindowGtk::OnDebouncedBoundsChanged() {
  gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_);
  shell_window_->OnNativeWindowChanged();
}

gboolean NativeAppWindowGtk::OnWindowState(GtkWidget* sender,
                                           GdkEventWindowState* event) {
  state_ = event->new_window_state;

  if (content_thinks_its_fullscreen_ &&
      !(state_ & GDK_WINDOW_STATE_FULLSCREEN)) {
    content_thinks_its_fullscreen_ = false;
    content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
    if (rvh)
      rvh->ExitFullscreen();
  }

  return FALSE;
}

gboolean NativeAppWindowGtk::OnButtonPress(GtkWidget* widget,
                                           GdkEventButton* event) {
  if (draggable_region_ && draggable_region_->contains(event->x, event->y)) {
    if (event->button == 1) {
      if (GDK_BUTTON_PRESS == event->type) {
        if (!suppress_window_raise_)
          gdk_window_raise(GTK_WIDGET(widget)->window);

        return gtk_window_util::HandleTitleBarLeftMousePress(
            GTK_WINDOW(widget), bounds_, event);
      } else if (GDK_2BUTTON_PRESS == event->type) {
        bool is_maximized = gdk_window_get_state(GTK_WIDGET(widget)->window) &
                            GDK_WINDOW_STATE_MAXIMIZED;
        if (is_maximized) {
          gtk_window_util::UnMaximize(GTK_WINDOW(widget),
              bounds_, restored_bounds_);
        } else {
          gtk_window_maximize(GTK_WINDOW(widget));
        }
        return TRUE;
      }
    } else if (event->button == 2) {
      gdk_window_lower(GTK_WIDGET(widget)->window);
      return TRUE;
    }
  }

  return FALSE;
}

void NativeAppWindowGtk::SetFullscreen(bool fullscreen) {
  content_thinks_its_fullscreen_ = fullscreen;
  if (fullscreen)
    gtk_window_fullscreen(window_);
  else
    gtk_window_unfullscreen(window_);
}

bool NativeAppWindowGtk::IsFullscreenOrPending() const {
  return content_thinks_its_fullscreen_;
}

void NativeAppWindowGtk::UpdateWindowIcon() {
  Profile* profile = shell_window_->profile();
  gfx::Image app_icon = shell_window_->app_icon();
  if (!app_icon.IsEmpty())
    gtk_util::SetWindowIcon(window_, profile, app_icon.ToGdkPixbuf());
  else
    gtk_util::SetWindowIcon(window_, profile);
}

void NativeAppWindowGtk::UpdateWindowTitle() {
  string16 title = shell_window_->GetTitle();
  gtk_window_set_title(window_, UTF16ToUTF8(title).c_str());
}

void NativeAppWindowGtk::HandleKeyboardEvent(
    const content::NativeWebKeyboardEvent& event) {
  // No-op.
}

void NativeAppWindowGtk::UpdateDraggableRegions(
    const std::vector<extensions::DraggableRegion>& regions) {
  // Draggable region is not supported for non-frameless window.
  if (!frameless_)
    return;

  draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
}

// static
NativeAppWindow* NativeAppWindow::Create(
    ShellWindow* shell_window,
    const ShellWindow::CreateParams& params) {
  return new NativeAppWindowGtk(shell_window, params);
}
<commit_msg>On Linux, Chrome App windows now set their window class to match the StartupWMClass field of the app shortcuts.<commit_after>// Copyright (c) 2012 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/ui/gtk/extensions/native_app_window_gtk.h"

#include "base/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/gtk_window_util.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/base/x/active_window_watcher_x.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"

namespace {

// The timeout in milliseconds before we'll get the true window position with
// gtk_window_get_position() after the last GTK configure-event signal.
const int kDebounceTimeoutMilliseconds = 100;

} // namespace

NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window,
                                       const ShellWindow::CreateParams& params)
    : shell_window_(shell_window),
      window_(NULL),
      state_(GDK_WINDOW_STATE_WITHDRAWN),
      is_active_(false),
      content_thinks_its_fullscreen_(false),
      frameless_(params.frame == ShellWindow::FRAME_NONE) {
  window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));

  gfx::NativeView native_view =
      web_contents()->GetView()->GetNativeView();
  gtk_container_add(GTK_CONTAINER(window_), native_view);

  if (params.bounds.x() != INT_MIN && params.bounds.y() != INT_MIN)
    gtk_window_move(window_, params.bounds.x(), params.bounds.y());

  // This is done to avoid a WM "feature" where setting the window size to
  // the monitor size causes the WM to set the EWMH for full screen mode.
  if (frameless_ &&
      gtk_window_util::BoundsMatchMonitorSize(window_, params.bounds)) {
    gtk_window_set_default_size(
        window_, params.bounds.width(), params.bounds.height() - 1);
  } else {
    gtk_window_set_default_size(
        window_, params.bounds.width(), params.bounds.height());
  }

  // make sure bounds_ and restored_bounds_ have correct values until we
  // get our first configure-event
  bounds_ = restored_bounds_ = params.bounds;
  gint x, y;
  gtk_window_get_position(window_, &x, &y);
  bounds_.set_origin(gfx::Point(x, y));

  // Hide titlebar when {frame: 'none'} specified on ShellWindow.
  if (frameless_)
    gtk_window_set_decorated(window_, false);

  int min_width = params.minimum_size.width();
  int min_height = params.minimum_size.height();
  int max_width = params.maximum_size.width();
  int max_height = params.maximum_size.height();
  GdkGeometry hints;
  int hints_mask = 0;
  if (min_width || min_height) {
    hints.min_height = min_height;
    hints.min_width = min_width;
    hints_mask |= GDK_HINT_MIN_SIZE;
  }
  if (max_width || max_height) {
    hints.max_height = max_height ? max_height : G_MAXINT;
    hints.max_width = max_width ? max_width : G_MAXINT;
    hints_mask |= GDK_HINT_MAX_SIZE;
  }
  if (hints_mask) {
    gtk_window_set_geometry_hints(
        window_,
        GTK_WIDGET(window_),
        &hints,
        static_cast<GdkWindowHints>(hints_mask));
  }

  // In some (older) versions of compiz, raising top-level windows when they
  // are partially off-screen causes them to get snapped back on screen, not
  // always even on the current virtual desktop.  If we are running under
  // compiz, suppress such raises, as they are not necessary in compiz anyway.
  if (ui::GuessWindowManager() == ui::WM_COMPIZ)
    suppress_window_raise_ = true;

  gtk_window_set_title(window_, extension()->name().c_str());

  std::string app_name = web_app::GenerateApplicationNameFromExtensionId(
      extension()->id());
  gtk_window_util::SetWindowCustomClass(window_,
      web_app::GetWMClassFromAppName(app_name));

  g_signal_connect(window_, "delete-event",
                   G_CALLBACK(OnMainWindowDeleteEventThunk), this);
  g_signal_connect(window_, "configure-event",
                   G_CALLBACK(OnConfigureThunk), this);
  g_signal_connect(window_, "window-state-event",
                   G_CALLBACK(OnWindowStateThunk), this);
  if (frameless_) {
    g_signal_connect(window_, "button-press-event",
                     G_CALLBACK(OnButtonPressThunk), this);
  }

  // Add the keybinding registry.
  extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk(
      shell_window_->profile(),
      window_,
      extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
      shell_window_));

  ui::ActiveWindowWatcherX::AddObserver(this);
}

NativeAppWindowGtk::~NativeAppWindowGtk() {
  ui::ActiveWindowWatcherX::RemoveObserver(this);
}

bool NativeAppWindowGtk::IsActive() const {
  if (ui::ActiveWindowWatcherX::WMSupportsActivation())
    return is_active_;

  // This still works even though we don't get the activation notification.
  return gtk_window_is_active(window_);
}

bool NativeAppWindowGtk::IsMaximized() const {
  return (state_ & GDK_WINDOW_STATE_MAXIMIZED);
}

bool NativeAppWindowGtk::IsMinimized() const {
  return (state_ & GDK_WINDOW_STATE_ICONIFIED);
}

bool NativeAppWindowGtk::IsFullscreen() const {
  return false;
}

gfx::NativeWindow NativeAppWindowGtk::GetNativeWindow() {
  return window_;
}

gfx::Rect NativeAppWindowGtk::GetRestoredBounds() const {
  return restored_bounds_;
}

gfx::Rect NativeAppWindowGtk::GetBounds() const {
  return bounds_;
}

void NativeAppWindowGtk::Show() {
  gtk_window_present(window_);
}

void NativeAppWindowGtk::ShowInactive() {
  gtk_window_set_focus_on_map(window_, false);
  gtk_widget_show(GTK_WIDGET(window_));
}

void NativeAppWindowGtk::Hide() {
  gtk_widget_hide(GTK_WIDGET(window_));
}

void NativeAppWindowGtk::Close() {
  shell_window_->OnNativeWindowChanged();

  // Cancel any pending callback from the window configure debounce timer.
  window_configure_debounce_timer_.Stop();

  GtkWidget* window = GTK_WIDGET(window_);
  // To help catch bugs in any event handlers that might get fired during the
  // destruction, set window_ to NULL before any handlers will run.
  window_ = NULL;

  // OnNativeClose does a delete this so no other members should
  // be accessed after. gtk_widget_destroy is safe (and must
  // be last).
  shell_window_->OnNativeClose();
  gtk_widget_destroy(window);
}

void NativeAppWindowGtk::Activate() {
  gtk_window_present(window_);
}

void NativeAppWindowGtk::Deactivate() {
  gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
}

void NativeAppWindowGtk::Maximize() {
  gtk_window_maximize(window_);
}

void NativeAppWindowGtk::Minimize() {
  gtk_window_iconify(window_);
}

void NativeAppWindowGtk::Restore() {
  if (IsMaximized())
    gtk_window_unmaximize(window_);
  else if (IsMinimized())
    gtk_window_deiconify(window_);
}

void NativeAppWindowGtk::SetBounds(const gfx::Rect& bounds) {
  gtk_window_move(window_, bounds.x(), bounds.y());
  gtk_window_util::SetWindowSize(window_,
      gfx::Size(bounds.width(), bounds.height()));
}

void NativeAppWindowGtk::FlashFrame(bool flash) {
  gtk_window_set_urgency_hint(window_, flash);
}

bool NativeAppWindowGtk::IsAlwaysOnTop() const {
  return false;
}

gfx::Insets NativeAppWindowGtk::GetFrameInsets() const {
  if (frameless_)
    return gfx::Insets();
  GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
  if (!gdk_window)
    return gfx::Insets();

  gint current_width = 0;
  gint current_height = 0;
  gtk_window_get_size(window_, &current_width, &current_height);
  gint current_x = 0;
  gint current_y = 0;
  gdk_window_get_position(gdk_window, &current_x, &current_y);
  GdkRectangle rect_with_decorations = {0};
  gdk_window_get_frame_extents(gdk_window,
                               &rect_with_decorations);

  int left_inset = current_x - rect_with_decorations.x;
  int top_inset = current_y - rect_with_decorations.y;
  return gfx::Insets(
      top_inset,
      left_inset,
      rect_with_decorations.height - current_height - top_inset,
      rect_with_decorations.width - current_width - left_inset);
}

void NativeAppWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
  // Do nothing if we're in the process of closing the browser window.
  if (!window_)
    return;

  is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
}

// Callback for the delete event.  This event is fired when the user tries to
// close the window (e.g., clicking on the X in the window manager title bar).
gboolean NativeAppWindowGtk::OnMainWindowDeleteEvent(GtkWidget* widget,
                                                     GdkEvent* event) {
  Close();

  // Return true to prevent the GTK window from being destroyed.  Close will
  // destroy it for us.
  return TRUE;
}

gboolean NativeAppWindowGtk::OnConfigure(GtkWidget* widget,
                                         GdkEventConfigure* event) {
  // We update |bounds_| but not |restored_bounds_| here.  The latter needs
  // to be updated conditionally when the window is non-maximized and non-
  // fullscreen, but whether those state updates have been processed yet is
  // window-manager specific.  We update |restored_bounds_| in the debounced
  // handler below, after the window state has been updated.
  bounds_.SetRect(event->x, event->y, event->width, event->height);

  // The GdkEventConfigure* we get here doesn't have quite the right
  // coordinates though (they're relative to the drawable window area, rather
  // than any window manager decorations, if enabled), so we need to call
  // gtk_window_get_position() to get the right values. (Otherwise session
  // restore, if enabled, will restore windows to incorrect positions.) That's
  // a round trip to the X server though, so we set a debounce timer and only
  // call it (in OnDebouncedBoundsChanged() below) after we haven't seen a
  // reconfigure event in a short while.
  // We don't use Reset() because the timer may not yet be running.
  // (In that case Stop() is a no-op.)
  window_configure_debounce_timer_.Stop();
  window_configure_debounce_timer_.Start(FROM_HERE,
      base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), this,
      &NativeAppWindowGtk::OnDebouncedBoundsChanged);

  return FALSE;
}

void NativeAppWindowGtk::OnDebouncedBoundsChanged() {
  gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_);
  shell_window_->OnNativeWindowChanged();
}

gboolean NativeAppWindowGtk::OnWindowState(GtkWidget* sender,
                                           GdkEventWindowState* event) {
  state_ = event->new_window_state;

  if (content_thinks_its_fullscreen_ &&
      !(state_ & GDK_WINDOW_STATE_FULLSCREEN)) {
    content_thinks_its_fullscreen_ = false;
    content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
    if (rvh)
      rvh->ExitFullscreen();
  }

  return FALSE;
}

gboolean NativeAppWindowGtk::OnButtonPress(GtkWidget* widget,
                                           GdkEventButton* event) {
  if (draggable_region_ && draggable_region_->contains(event->x, event->y)) {
    if (event->button == 1) {
      if (GDK_BUTTON_PRESS == event->type) {
        if (!suppress_window_raise_)
          gdk_window_raise(GTK_WIDGET(widget)->window);

        return gtk_window_util::HandleTitleBarLeftMousePress(
            GTK_WINDOW(widget), bounds_, event);
      } else if (GDK_2BUTTON_PRESS == event->type) {
        bool is_maximized = gdk_window_get_state(GTK_WIDGET(widget)->window) &
                            GDK_WINDOW_STATE_MAXIMIZED;
        if (is_maximized) {
          gtk_window_util::UnMaximize(GTK_WINDOW(widget),
              bounds_, restored_bounds_);
        } else {
          gtk_window_maximize(GTK_WINDOW(widget));
        }
        return TRUE;
      }
    } else if (event->button == 2) {
      gdk_window_lower(GTK_WIDGET(widget)->window);
      return TRUE;
    }
  }

  return FALSE;
}

void NativeAppWindowGtk::SetFullscreen(bool fullscreen) {
  content_thinks_its_fullscreen_ = fullscreen;
  if (fullscreen)
    gtk_window_fullscreen(window_);
  else
    gtk_window_unfullscreen(window_);
}

bool NativeAppWindowGtk::IsFullscreenOrPending() const {
  return content_thinks_its_fullscreen_;
}

void NativeAppWindowGtk::UpdateWindowIcon() {
  Profile* profile = shell_window_->profile();
  gfx::Image app_icon = shell_window_->app_icon();
  if (!app_icon.IsEmpty())
    gtk_util::SetWindowIcon(window_, profile, app_icon.ToGdkPixbuf());
  else
    gtk_util::SetWindowIcon(window_, profile);
}

void NativeAppWindowGtk::UpdateWindowTitle() {
  string16 title = shell_window_->GetTitle();
  gtk_window_set_title(window_, UTF16ToUTF8(title).c_str());
}

void NativeAppWindowGtk::HandleKeyboardEvent(
    const content::NativeWebKeyboardEvent& event) {
  // No-op.
}

void NativeAppWindowGtk::UpdateDraggableRegions(
    const std::vector<extensions::DraggableRegion>& regions) {
  // Draggable region is not supported for non-frameless window.
  if (!frameless_)
    return;

  draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
}

// static
NativeAppWindow* NativeAppWindow::Create(
    ShellWindow* shell_window,
    const ShellWindow::CreateParams& params) {
  return new NativeAppWindowGtk(shell_window, params);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007-2008, Python File Format Interface
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the Python File Format Interface
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <fstream>

#include "pyffi/object_models/xml/file_format.hpp"
#include "pyffi/exceptions.hpp"

namespace pyffi
{

namespace object_models
{

namespace xml
{

namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;

template <typename Iterator>
struct xml_skipper : qi::grammar<Iterator> {
	qi::rule<Iterator> start;

	xml_skipper()
		: xml_skipper::base_type(start) {
		start =
		    qi::space
		    //[std::cout << phoenix::val("SPACE") << std::endl]
		    |
		    qi::lit("<!--")
		    //[std::cout << phoenix::val("XMLCOMMENT=")]
		    >> *(!qi::lit("-->")
		         >> qi::char_
		         //[std::cout << qi::_1]
		        )
		    >> qi::lit("-->");
	};
};

template <typename Iterator, typename Skipper = qi::grammar<Iterator> >
struct xml_parser : qi::grammar<Iterator, Skipper> {
	qi::rule<Iterator, Skipper> tag_fileformat;
	qi::rule<Iterator, Skipper> comment;
	qi::rule<Iterator, Skipper> tag_version;
	qi::rule<Iterator, Skipper> tag_basic;
	qi::rule<Iterator, Skipper> tag_enum;
	qi::rule<Iterator, Skipper> tag_option;
	qi::rule<Iterator, Skipper> tag_bitflags;
	qi::rule<Iterator, Skipper> tag_struct;
	qi::rule<Iterator, Skipper> tag_add;
	qi::rule<Iterator, std::string(std::string), Skipper> attr_string;
	qi::rule<Iterator, unsigned(std::string), Skipper> attr_version;

	xml_parser()
		: xml_parser::base_type(tag_fileformat, "fileformatxml") {
		using phoenix::construct;
		using phoenix::val;
		using qi::char_;
		using qi::eoi;
		using qi::eps;
		using qi::fail;
		using qi::graph;
		using qi::lexeme;
		using qi::lit;
		using qi::on_error;
		using qi::space;
		using qi::uint_;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		using qi::_4;
		using qi::_r1;
		using qi::_val;

		tag_fileformat =
		    -(lit("<?xml")
		      [std::cout << val("XML") << std::endl]
		      >> *(!lit("?>") >> char_)
		      >> lit("?>"))
		    >> -(lit("<!DOCTYPE")
		         [std::cout << val("DOCTYPE") << std::endl]
		         >> lit("niftoolsxml")
		         >> lit(">"))
		    >> lit("<niftoolsxml")
		    [std::cout << val("NIFTOOLSXML") << std::endl]
		    >> -(lit("version") >> lit("=") >> lit("\"0.7.0.0\""))
		    >> lit(">")
		    >> *(tag_version | tag_basic | tag_enum)
		    //>> *(!lit("</niftoolsxml>") >> char_) // temporary skip rule
		    >> lit("</niftoolsxml>")
		    >> eoi;

		comment = *lexeme[+(!char_('<') >> graph)];

		tag_basic =
		    lit("<basic")
		    [std::cout << val("BASIC=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        | attr_string(std::string("count"))
		        | attr_string(std::string("niflibtype"))
		        | attr_string(std::string("nifskopetype"))
		        | attr_string(std::string("istemplate"))
		    )
		    >> char_('>')
		    >> comment
		    >> lit("</basic>");

		tag_enum =
		    lit("<enum")
		    [std::cout << val("ENUM=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        |
		        attr_string(std::string("storage"))
		        [std::cout << val("(") << _1 << ")" << std::endl]
		    )
		    >> char_('>')
		    >> comment
		    >> *tag_option
		    >> lit("</enum>");

		tag_option =
		    lit("<option")
		    [std::cout << val("OPTION=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        |
		        attr_string(std::string("value"))
		    )
		    >> char_('>')
		    >> comment
		    >> lit("</option>");

		tag_version =
		    lit("<version")
		    [std::cout << val("VERSION=")]
		    >> attr_version(std::string("num"))
		    [std::cout << _1 << std::endl]
		    >> char_('>')
		    >> comment
		    >> lit("</version>");

		attr_string %=
		    lit(_r1) >> '='
		    >> lexeme['"' >> *(char_ - '"') >> '"'];

		attr_version =
		    lit(_r1)[_val = 0] >> '='
		    >> '"' >> (uint_[_val = _val * 256 + _1] % '.') >> '"';

		tag_fileformat.name("<niftoolsxml>...</niftoolsxml>");
		comment.name("...");
		tag_version.name("<version>...</version>");
		tag_basic.name("<basic>...</basic>");
		attr_string.name("attribute (string)");
		attr_version.name("attribute (version)");

		on_error<fail>(
		    tag_fileformat,
		    std::cout
		    << val("Error! Expecting ")
		    << _4                               // what failed?
		    << val(" here: \"")
		    << construct<std::string>(_3, _2)   // iterators to error-pos, end
		    << val("\"")
		    << std::endl
		);
	};
};

/*
 * Main entry point for parsing an xml file.
 */

FileFormat::FileFormat(const std::string & filename)
{
	// open file, disable skipping of whitespace
	std::ifstream in(filename.c_str());
	if (in.fail()) {
		throw io_error("Could not open '" + filename + "'.");
	}
	in.unsetf(std::ios::skipws);
	std::cout << "PARSING " << filename << std::endl;

	// wrap istream into iterator
	boost::spirit::istream_iterator first(in);
	boost::spirit::istream_iterator last;

	// create skip parser
	xml_skipper<boost::spirit::istream_iterator> skipper;

	// create parser
	xml_parser<boost::spirit::istream_iterator> parser;

	// use iterator to parse file data
	bool r = qi::phrase_parse(first, last, parser, skipper);

	// fail if we did not get a full match
	if (!r || first != last)
		throw syntax_error("Syntax error while parsing '" + filename + "'.");
};

}; // namespace xml

}; // namespace object_models

}; // namespace pyffi
<commit_msg>Added struct tag.<commit_after>/*

Copyright (c) 2007-2008, Python File Format Interface
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the Python File Format Interface
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <fstream>

#include "pyffi/object_models/xml/file_format.hpp"
#include "pyffi/exceptions.hpp"

namespace pyffi
{

namespace object_models
{

namespace xml
{

namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;

template <typename Iterator>
struct xml_skipper : qi::grammar<Iterator> {
	qi::rule<Iterator> start;

	xml_skipper()
		: xml_skipper::base_type(start) {
		start =
		    qi::space
		    //[std::cout << phoenix::val("SPACE") << std::endl]
		    |
		    qi::lit("<!--")
		    //[std::cout << phoenix::val("XMLCOMMENT=")]
		    >> *(!qi::lit("-->")
		         >> qi::char_
		         //[std::cout << qi::_1]
		        )
		    >> qi::lit("-->");
	};
};

template <typename Iterator, typename Skipper = qi::grammar<Iterator> >
struct xml_parser : qi::grammar<Iterator, Skipper> {
	qi::rule<Iterator, Skipper> tag_fileformat;
	qi::rule<Iterator, Skipper> comment;
	qi::rule<Iterator, Skipper> tag_version;
	qi::rule<Iterator, Skipper> tag_basic;
	qi::rule<Iterator, Skipper> tag_enum;
	qi::rule<Iterator, Skipper> tag_option;
	qi::rule<Iterator, Skipper> tag_bitflags;
	qi::rule<Iterator, Skipper> tag_struct;
	qi::rule<Iterator, Skipper> tag_add;
	qi::rule<Iterator, std::string(std::string), Skipper> attr_string;
	qi::rule<Iterator, unsigned(std::string), Skipper> attr_version;

	xml_parser()
		: xml_parser::base_type(tag_fileformat, "fileformatxml") {
		using phoenix::construct;
		using phoenix::val;
		using qi::char_;
		using qi::eoi;
		using qi::eps;
		using qi::fail;
		using qi::graph;
		using qi::lexeme;
		using qi::lit;
		using qi::on_error;
		using qi::space;
		using qi::uint_;
		using qi::_1;
		using qi::_2;
		using qi::_3;
		using qi::_4;
		using qi::_r1;
		using qi::_val;

		tag_fileformat =
		    -(lit("<?xml")
		      [std::cout << val("XML") << std::endl]
		      >> *(!lit("?>") >> char_)
		      >> lit("?>"))
		    >> -(lit("<!DOCTYPE")
		         [std::cout << val("DOCTYPE") << std::endl]
		         >> lit("niftoolsxml")
		         >> lit(">"))
		    >> lit("<niftoolsxml")
		    [std::cout << val("NIFTOOLSXML") << std::endl]
		    >> -(lit("version") >> lit("=") >> lit("\"0.7.0.0\""))
		    >> lit(">")
		    >> *(tag_version | tag_basic | tag_enum | tag_struct)
		    //>> *(!lit("</niftoolsxml>") >> char_) // temporary skip rule
		    >> lit("</niftoolsxml>")
		    >> eoi;

		comment = *lexeme[+(!char_('<') >> graph)];

		tag_add =
		    lit("<add")
		    [std::cout << val("ADD=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        | attr_string(std::string("type"))
		        | attr_string(std::string("default"))
		        | attr_version(std::string("ver1"))
		        | attr_version(std::string("ver2"))
		        | attr_string(std::string("cond"))
		        | attr_string(std::string("arr1"))
		        | attr_string(std::string("arr2"))
		        | attr_string(std::string("template"))
		        | attr_string(std::string("vercond"))
		    )
		    >> char_('>')
		    >> comment
		    >> lit("</add>");

		tag_basic =
		    lit("<basic")
		    [std::cout << val("BASIC=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        | attr_string(std::string("count"))
		        | attr_string(std::string("niflibtype"))
		        | attr_string(std::string("nifskopetype"))
		        | attr_string(std::string("istemplate"))
		    )
		    >> char_('>')
		    >> comment
		    >> lit("</basic>");

		tag_enum =
		    lit("<enum")
		    [std::cout << val("ENUM=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        |
		        attr_string(std::string("storage"))
		        [std::cout << val("(") << _1 << ")" << std::endl]
		    )
		    >> char_('>')
		    >> comment
		    >> *tag_option
		    >> lit("</enum>");

		tag_option =
		    lit("<option")
		    [std::cout << val("OPTION=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        |
		        attr_string(std::string("value"))
		    )
		    >> char_('>')
		    >> comment
		    >> lit("</option>");

		tag_struct =
		    (lit("<struct") | lit("<compound") | lit("<niobject"))
		    [std::cout << val("STRUCT=")]
		    >> *(
		        attr_string(std::string("name"))
		        [std::cout << _1 << std::endl]
		        |
		        attr_string(std::string("inherit"))
		        [std::cout << val("(") << _1 << ")" << std::endl]
		        | attr_string(std::string("niflibtype"))
		        | attr_string(std::string("nifskopetype"))
		        | attr_string(std::string("abstract"))
		        | attr_string(std::string("ver1"))
		        | attr_string(std::string("ver2"))
		    )
		    >> char_('>')
		    >> comment
		    >> *tag_add
		    >> (lit("</struct>") | lit("</compound>") | lit("</niobject>"));

		tag_version =
		    lit("<version")
		    [std::cout << val("VERSION=")]
		    >> attr_version(std::string("num"))
		    [std::cout << _1 << std::endl]
		    >> char_('>')
		    >> comment
		    >> lit("</version>");

		attr_string %=
		    lit(_r1) >> '='
		    >> lexeme['"' >> *(char_ - '"') >> '"'];

		attr_version =
		    lit(_r1)[_val = 0] >> '='
		    >> '"' >> (uint_[_val = _val * 256 + _1] % '.') >> '"';

		tag_fileformat.name("<niftoolsxml>...</niftoolsxml>");
		comment.name("...");
		tag_version.name("<version>...</version>");
		tag_basic.name("<basic>...</basic>");
		attr_string.name("attribute (string)");
		attr_version.name("attribute (version)");

		on_error<fail>(
		    tag_fileformat,
		    std::cout
		    << val("Error! Expecting ")
		    << _4                               // what failed?
		    << val(" here: \"")
		    << construct<std::string>(_3, _2)   // iterators to error-pos, end
		    << val("\"")
		    << std::endl
		);
	};
};

/*
 * Main entry point for parsing an xml file.
 */

FileFormat::FileFormat(const std::string & filename)
{
	// open file, disable skipping of whitespace
	std::ifstream in(filename.c_str());
	if (in.fail()) {
		throw io_error("Could not open '" + filename + "'.");
	}
	in.unsetf(std::ios::skipws);
	std::cout << "PARSING " << filename << std::endl;

	// wrap istream into iterator
	boost::spirit::istream_iterator first(in);
	boost::spirit::istream_iterator last;

	// create skip parser
	xml_skipper<boost::spirit::istream_iterator> skipper;

	// create parser
	xml_parser<boost::spirit::istream_iterator> parser;

	// use iterator to parse file data
	bool r = qi::phrase_parse(first, last, parser, skipper);

	// fail if we did not get a full match
	if (!r || first != last)
		throw syntax_error("Syntax error while parsing '" + filename + "'.");
};

}; // namespace xml

}; // namespace object_models

}; // namespace pyffi
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_LOGGED_RESOURCES_HXX
#define INCLUDED_LOGGED_RESOURCES_HXX

#include "WW8ResourceModel.hxx"
#include "TagLogger.hxx"

namespace writerfilter
{

class LoggedResourcesHelper
{
public:
    explicit LoggedResourcesHelper(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedResourcesHelper();

    void startElement(const string & sElement);
    void endElement(const string & sElement);
    void chars(const ::rtl::OUString & rChars);
    void chars(const string & rChars);
    void attribute(const string & rName, const string & rValue);
    void attribute(const string & rName, sal_uInt32 nValue);

    void setPrefix(const string & rPrefix);

private:
    TagLogger::Pointer_t mpLogger;
    string msPrefix;
};

class WRITERFILTER_DLLPUBLIC LoggedStream : public Stream
{
public:
    explicit LoggedStream(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedStream();

    void startSectionGroup();
    void endSectionGroup();
    void startParagraphGroup();
    void endParagraphGroup();
    void startCharacterGroup();
    void endCharacterGroup();
    void startShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape );
    void endShape();
    void text(const sal_uInt8 * data, size_t len);
    void utext(const sal_uInt8 * data, size_t len);
    void props(writerfilter::Reference<Properties>::Pointer_t ref);
    void table(Id name, writerfilter::Reference<Table>::Pointer_t ref);
    void substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref);
    void info(const string & info);

protected:
    virtual void lcl_startSectionGroup() = 0;
    virtual void lcl_endSectionGroup() = 0;
    virtual void lcl_startParagraphGroup() = 0;
    virtual void lcl_endParagraphGroup() = 0;
    virtual void lcl_startCharacterGroup() = 0;
    virtual void lcl_endCharacterGroup() = 0;
    virtual void lcl_startShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape )  = 0;
    virtual void lcl_endShape() = 0;
    virtual void lcl_text(const sal_uInt8 * data, size_t len) = 0;
    virtual void lcl_utext(const sal_uInt8 * data, size_t len) = 0;
    virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) = 0;
    virtual void lcl_table(Id name, writerfilter::Reference<Table>::Pointer_t ref) = 0;
    virtual void lcl_substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) = 0;
    virtual void lcl_info(const string & info) = 0;

    LoggedResourcesHelper mHelper;
};

class WRITERFILTER_DLLPUBLIC LoggedProperties : public Properties
{
public:
    explicit LoggedProperties(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedProperties();

    void attribute(Id name, Value & val);
    void sprm(Sprm & sprm);

protected:
    virtual void lcl_attribute(Id name, Value & val) = 0;
    virtual void lcl_sprm(Sprm & sprm) = 0;

    LoggedResourcesHelper mHelper;
};

class WRITERFILTER_DLLPUBLIC LoggedTable : public Table
{
public:
    explicit LoggedTable(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedTable();

    void entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref);

protected:
    virtual void lcl_entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref) = 0;

    LoggedResourcesHelper mHelper;
};

}
#endif // INCLUDED_LOGGED_RESOURCES_HXX
<commit_msg>Export the LoggedResourcesHelper class<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_LOGGED_RESOURCES_HXX
#define INCLUDED_LOGGED_RESOURCES_HXX

#include "WW8ResourceModel.hxx"
#include "TagLogger.hxx"

#include <WriterFilterDllApi.hxx>

namespace writerfilter
{

class WRITERFILTER_DLLPUBLIC LoggedResourcesHelper
{
public:
    explicit LoggedResourcesHelper(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedResourcesHelper();

    void startElement(const string & sElement);
    void endElement(const string & sElement);
    void chars(const ::rtl::OUString & rChars);
    void chars(const string & rChars);
    void attribute(const string & rName, const string & rValue);
    void attribute(const string & rName, sal_uInt32 nValue);

    void setPrefix(const string & rPrefix);

private:
    TagLogger::Pointer_t mpLogger;
    string msPrefix;
};

class WRITERFILTER_DLLPUBLIC LoggedStream : public Stream
{
public:
    explicit LoggedStream(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedStream();

    void startSectionGroup();
    void endSectionGroup();
    void startParagraphGroup();
    void endParagraphGroup();
    void startCharacterGroup();
    void endCharacterGroup();
    void startShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape );
    void endShape();
    void text(const sal_uInt8 * data, size_t len);
    void utext(const sal_uInt8 * data, size_t len);
    void props(writerfilter::Reference<Properties>::Pointer_t ref);
    void table(Id name, writerfilter::Reference<Table>::Pointer_t ref);
    void substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref);
    void info(const string & info);

protected:
    virtual void lcl_startSectionGroup() = 0;
    virtual void lcl_endSectionGroup() = 0;
    virtual void lcl_startParagraphGroup() = 0;
    virtual void lcl_endParagraphGroup() = 0;
    virtual void lcl_startCharacterGroup() = 0;
    virtual void lcl_endCharacterGroup() = 0;
    virtual void lcl_startShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xShape )  = 0;
    virtual void lcl_endShape() = 0;
    virtual void lcl_text(const sal_uInt8 * data, size_t len) = 0;
    virtual void lcl_utext(const sal_uInt8 * data, size_t len) = 0;
    virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) = 0;
    virtual void lcl_table(Id name, writerfilter::Reference<Table>::Pointer_t ref) = 0;
    virtual void lcl_substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) = 0;
    virtual void lcl_info(const string & info) = 0;

    LoggedResourcesHelper mHelper;
};

class WRITERFILTER_DLLPUBLIC LoggedProperties : public Properties
{
public:
    explicit LoggedProperties(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedProperties();

    void attribute(Id name, Value & val);
    void sprm(Sprm & sprm);

protected:
    virtual void lcl_attribute(Id name, Value & val) = 0;
    virtual void lcl_sprm(Sprm & sprm) = 0;

    LoggedResourcesHelper mHelper;
};

class WRITERFILTER_DLLPUBLIC LoggedTable : public Table
{
public:
    explicit LoggedTable(TagLogger::Pointer_t pLogger, const string & sPrefix);
    virtual ~LoggedTable();

    void entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref);

protected:
    virtual void lcl_entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref) = 0;

    LoggedResourcesHelper mHelper;
};

}
#endif // INCLUDED_LOGGED_RESOURCES_HXX
<|endoftext|>


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

#include "base/time/time.h"
#include "chrome/test/base/chrome_render_view_test.h"
#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "content/public/test/mock_render_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"

using blink::WebString;
using blink::WebURLError;

typedef ChromeRenderViewTest FormAutocompleteTest;

namespace autofill {

namespace {

// Helper function to verify the form-related messages received from the
// renderer. The same data is expected in both messages. Depending on
// |expect_submitted_message|, will verify presence of FormSubmitted message.
void VerifyReceivedRendererMessages(content::MockRenderThread* render_thread,
                                    bool expect_submitted_message) {
  const IPC::Message* will_submit_message =
      render_thread->sink().GetFirstMessageMatching(
          AutofillHostMsg_WillSubmitForm::ID);
  const IPC::Message* submitted_message =
      render_thread->sink().GetFirstMessageMatching(
          AutofillHostMsg_FormSubmitted::ID);
  ASSERT_TRUE(will_submit_message != NULL);
  ASSERT_EQ(expect_submitted_message, submitted_message != NULL);

  // The tuple also includes a timestamp, which is ignored.
  base::Tuple<FormData, base::TimeTicks> will_submit_forms;
  AutofillHostMsg_WillSubmitForm::Read(will_submit_message, &will_submit_forms);
  ASSERT_EQ(2U, base::get<0>(will_submit_forms).fields.size());

  FormFieldData& will_submit_form_field =
      base::get<0>(will_submit_forms).fields[0];
  EXPECT_EQ(WebString("fname"), will_submit_form_field.name);
  EXPECT_EQ(WebString("Rick"), will_submit_form_field.value);
  will_submit_form_field = base::get<0>(will_submit_forms).fields[1];
  EXPECT_EQ(WebString("lname"), will_submit_form_field.name);
  EXPECT_EQ(WebString("Deckard"), will_submit_form_field.value);

  if (expect_submitted_message) {
    base::Tuple<FormData> submitted_forms;
    AutofillHostMsg_FormSubmitted::Read(submitted_message, &submitted_forms);
    ASSERT_EQ(2U, base::get<0>(submitted_forms).fields.size());

    FormFieldData& submitted_field = base::get<0>(submitted_forms).fields[0];
    EXPECT_EQ(WebString("fname"), submitted_field.name);
    EXPECT_EQ(WebString("Rick"), submitted_field.value);
    submitted_field = base::get<0>(submitted_forms).fields[1];
    EXPECT_EQ(WebString("lname"), submitted_field.name);
    EXPECT_EQ(WebString("Deckard"), submitted_field.value);
  }
}

}  // end namespace

// Tests that submitting a form generates WillSubmitForm and FormSubmitted
// messages with the form fields.
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_NormalFormSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm'><input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/></form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that submitting a form that prevents the submit event from propagating
// will only send the WillSubmitForm message.
TEST_F(FormAutocompleteTest, SubmitEventPrevented) {
  // Load a form.
  LoadHTML(
      "<form id='myForm'><input name='fname' value='Rick'/>"
      "<input name='lname' value='Deckard'/><input type=submit></form>"
      "");

  // Submit the form.
  ExecuteJavaScript(
      "var form = document.forms[0];"
      "form.onsubmit = function(event) { event.preventDefault(); };"
      "document.querySelector('input[type=submit]').click();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 false /* expect_submitted_message */);
}

// Tests that submitting a form that has autocomplete="off" generates
// WillSubmitForm and FormSubmitted messages.
TEST_F(FormAutocompleteTest, AutoCompleteOffFormSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm' autocomplete='off'>"
           "<input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/>"
           "</form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that fields with autocomplete off are submitted.
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_AutoCompleteOffInputSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm'>"
           "<input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard' autocomplete='off'/>"
           "</form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that submitting a form that has been dynamically set as autocomplete
// off generates WillSubmitForm and FormSubmitted messages.
// Note: We previously did the opposite, for bug http://crbug.com/36520
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_DynamicAutoCompleteOffFormSubmit) {
  LoadHTML("<form id='myForm'><input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/></form>");

  blink::WebElement element =
      GetMainFrame()->document().getElementById(blink::WebString("myForm"));
  ASSERT_FALSE(element.isNull());
  blink::WebFormElement form = element.to<blink::WebFormElement>();
  EXPECT_TRUE(form.autoComplete());

  // Dynamically mark the form as autocomplete off.
  ExecuteJavaScript("document.getElementById('myForm')."
                    "setAttribute('autocomplete', 'off');");
  ProcessPendingMessages();
  EXPECT_FALSE(form.autoComplete());

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

}  // namespace autofill
<commit_msg>Disable one more form autocomplete test I missed.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/time/time.h"
#include "chrome/test/base/chrome_render_view_test.h"
#include "components/autofill/content/common/autofill_messages.h"
#include "components/autofill/core/common/form_data.h"
#include "content/public/test/mock_render_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"

using blink::WebString;
using blink::WebURLError;

typedef ChromeRenderViewTest FormAutocompleteTest;

namespace autofill {

namespace {

// Helper function to verify the form-related messages received from the
// renderer. The same data is expected in both messages. Depending on
// |expect_submitted_message|, will verify presence of FormSubmitted message.
void VerifyReceivedRendererMessages(content::MockRenderThread* render_thread,
                                    bool expect_submitted_message) {
  const IPC::Message* will_submit_message =
      render_thread->sink().GetFirstMessageMatching(
          AutofillHostMsg_WillSubmitForm::ID);
  const IPC::Message* submitted_message =
      render_thread->sink().GetFirstMessageMatching(
          AutofillHostMsg_FormSubmitted::ID);
  ASSERT_TRUE(will_submit_message != NULL);
  ASSERT_EQ(expect_submitted_message, submitted_message != NULL);

  // The tuple also includes a timestamp, which is ignored.
  base::Tuple<FormData, base::TimeTicks> will_submit_forms;
  AutofillHostMsg_WillSubmitForm::Read(will_submit_message, &will_submit_forms);
  ASSERT_EQ(2U, base::get<0>(will_submit_forms).fields.size());

  FormFieldData& will_submit_form_field =
      base::get<0>(will_submit_forms).fields[0];
  EXPECT_EQ(WebString("fname"), will_submit_form_field.name);
  EXPECT_EQ(WebString("Rick"), will_submit_form_field.value);
  will_submit_form_field = base::get<0>(will_submit_forms).fields[1];
  EXPECT_EQ(WebString("lname"), will_submit_form_field.name);
  EXPECT_EQ(WebString("Deckard"), will_submit_form_field.value);

  if (expect_submitted_message) {
    base::Tuple<FormData> submitted_forms;
    AutofillHostMsg_FormSubmitted::Read(submitted_message, &submitted_forms);
    ASSERT_EQ(2U, base::get<0>(submitted_forms).fields.size());

    FormFieldData& submitted_field = base::get<0>(submitted_forms).fields[0];
    EXPECT_EQ(WebString("fname"), submitted_field.name);
    EXPECT_EQ(WebString("Rick"), submitted_field.value);
    submitted_field = base::get<0>(submitted_forms).fields[1];
    EXPECT_EQ(WebString("lname"), submitted_field.name);
    EXPECT_EQ(WebString("Deckard"), submitted_field.value);
  }
}

}  // end namespace

// Tests that submitting a form generates WillSubmitForm and FormSubmitted
// messages with the form fields.
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_NormalFormSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm'><input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/></form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that submitting a form that prevents the submit event from propagating
// will only send the WillSubmitForm message.
TEST_F(FormAutocompleteTest, SubmitEventPrevented) {
  // Load a form.
  LoadHTML(
      "<form id='myForm'><input name='fname' value='Rick'/>"
      "<input name='lname' value='Deckard'/><input type=submit></form>"
      "");

  // Submit the form.
  ExecuteJavaScript(
      "var form = document.forms[0];"
      "form.onsubmit = function(event) { event.preventDefault(); };"
      "document.querySelector('input[type=submit]').click();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 false /* expect_submitted_message */);
}

// Tests that submitting a form that has autocomplete="off" generates
// WillSubmitForm and FormSubmitted messages.
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_AutoCompleteOffFormSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm' autocomplete='off'>"
           "<input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/>"
           "</form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that fields with autocomplete off are submitted.
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_AutoCompleteOffInputSubmit) {
  // Load a form.
  LoadHTML("<form id='myForm'>"
           "<input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard' autocomplete='off'/>"
           "</form>");

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

// Tests that submitting a form that has been dynamically set as autocomplete
// off generates WillSubmitForm and FormSubmitted messages.
// Note: We previously did the opposite, for bug http://crbug.com/36520
// Flaky: http://crbug.com/500851.
TEST_F(FormAutocompleteTest, DISABLED_DynamicAutoCompleteOffFormSubmit) {
  LoadHTML("<form id='myForm'><input name='fname' value='Rick'/>"
           "<input name='lname' value='Deckard'/></form>");

  blink::WebElement element =
      GetMainFrame()->document().getElementById(blink::WebString("myForm"));
  ASSERT_FALSE(element.isNull());
  blink::WebFormElement form = element.to<blink::WebFormElement>();
  EXPECT_TRUE(form.autoComplete());

  // Dynamically mark the form as autocomplete off.
  ExecuteJavaScript("document.getElementById('myForm')."
                    "setAttribute('autocomplete', 'off');");
  ProcessPendingMessages();
  EXPECT_FALSE(form.autoComplete());

  // Submit the form.
  ExecuteJavaScript("document.getElementById('myForm').submit();");
  ProcessPendingMessages();

  VerifyReceivedRendererMessages(render_thread_.get(),
                                 true /* expect_submitted_message */);
}

}  // namespace autofill
<|endoftext|>


<commit_before>#include "card.hpp"

#include <iostream>

void card::assign(rank r, suit s) {
    rank_ = r;
    suit_ = s;
}

bool operator==(card a, card b) {
    return a.get_rank() == b.get_rank() and
           a.get_suit() == b.get_suit();
}

bool operator!=(card a, card b) {
    return not (a == b);
}

std::ostream& operator<<(std::ostream& out, card c) {
    out << c.get_rank() << " " << c.get_suit();
    return out;
}

std::istream& operator>>(std::istream& in, card c) {
    char s{}, r{};
    in >> r;
    in >> s;
    c.assign(r, s);

    return in;
}

bool acehigh_compare(card a, card b) {
    return a.get_rank() < b.get_rank();
}

bool acelow_compare(card a, card b) {
    return (card::ace == a.get_rank())
           ? true
           : a.get_rank() < b.get_rank();
}

card_generator::card_generator()
    : rankIndex_{ 2 }, suitIndex_{ card::ace } { }

card card_generator::operator()() {
    card c = card(rankIndex_, suitIndex_);

    if(++rankIndex_ > card::ace) {
        if (card::spades == suitIndex_) {
            rankIndex_ = 2;
            suitIndex_ = card::diamonds;
        }
        else {
            rankIndex_ = 2;
            ++suitIndex_;
        }
    }

    return c;
}
<commit_msg>ch-53: modify the 3-d example for chapter 53<commit_after>#include "card.hpp"

#include <iostream>

void card::assign(rank r, suit s) {
    rank_ = r;
    suit_ = s;
}

bool operator==(card a, card b) {
    return a.get_rank() == b.get_rank() and
           a.get_suit() == b.get_suit();
}

bool operator!=(card a, card b) {
    return not (a == b);
}

std::ostream& operator<<(std::ostream& out, card c) {
    out << int(c.get_rank()) << " " << int(c.get_suit());
    return out;
}

std::istream& operator>>(std::istream& in, card c) {
    char s{}, r{};
    in >> r;
    in >> s;
    c.assign(r, s);

    return in;
}

bool acehigh_compare(card a, card b) {
    return a.get_rank() < b.get_rank();
}

bool acelow_compare(card a, card b) {
    return (card::ace == a.get_rank())
           ? true
           : a.get_rank() < b.get_rank();
}

card_generator::card_generator()
    : rankIndex_{ 2 }, suitIndex_{ card::diamonds } { }

card card_generator::operator()() {
    card c = card(rankIndex_, suitIndex_);

    if(++rankIndex_ > card::ace) {
        if (card::spades == suitIndex_) {
            rankIndex_ = 2;
            suitIndex_ = card::diamonds;
        }
        else {
            rankIndex_ = 2;
            ++suitIndex_;
        }
    }

    return c;
}
<|endoftext|>


<commit_before>/*
  Упорядочить три числа в порядке возрастания.
  C++ версия
*/

#include <iostream> // подключение ввода/вывода в консоль
#include <clocale>  // Для Windows - подключение вывода русских букв в консоль

int main()
{
    std::setlocale(LC_ALL, "RUS");

    int x, y, z;

    std::cout << "x: ";
    std::cin >> x;

    std::cout << "y: ";
    std::cin >> y;

    std::cout << "z: ";
    std::cin >> z;

    // Печатаем некоторый текст с переносом
    std::cout << "Результат: \n";

    if (x > y) {
        if (y > z) {
            // Обращаем внимание, как форматируется строка для вывода на экран. В частности, отступы
            std::cout << "z = " << z << "\n";
            std::cout << "y = " << y << "\n";
            std::cout << "x = " << x << "\n";
        } else {
            std::cout << "y = " << y << "\n";

            if (x > z) {
                std::cout << "z = " << z << "\n";
                std::cout << "x = " << x << "\n";
            } else {
                std::cout << "x = " << x << "\n";
                std::cout << "z = " << z << "\n";
            }
        }
    } else {
        if (x > z) {
            std::cout << "z = " << z << "\n";
            std::cout << "x = " << x << "\n";
            printf("y = %d\n", y);
        } else {
            std::cout << "x = " << x << "\n";

            if (y > z) {
                std::cout << "z = " << z << "\n";
                std::cout << "y = " << y << "\n";
            } else {
                std::cout << "y = " << y << "\n";
                std::cout << "z = " << z << "\n";
            }
        }
    }

    return 0;
}
<commit_msg>fix console output in 1.cpp<commit_after>/*
  Упорядочить три числа в порядке возрастания.
  C++ версия
*/

#include <iostream> // подключение ввода/вывода в консоль
#include <clocale>  // Для Windows - подключение вывода русских букв в консоль

int main()
{
    std::setlocale(LC_ALL, "RUS");

    int x, y, z;

    std::cout << "x: ";
    std::cin >> x;

    std::cout << "y: ";
    std::cin >> y;

    std::cout << "z: ";
    std::cin >> z;

    // Печатаем некоторый текст с переносом
    std::cout << "Результат: \n";

    if (x > y) {
        if (y > z) {
            // Обращаем внимание, как форматируется строка для вывода на экран. В частности, отступы
            std::cout << "z = " << z << "\n";
            std::cout << "y = " << y << "\n";
            std::cout << "x = " << x << "\n";
        } else {
            std::cout << "y = " << y << "\n";

            if (x > z) {
                std::cout << "z = " << z << "\n";
                std::cout << "x = " << x << "\n";
            } else {
                std::cout << "x = " << x << "\n";
                std::cout << "z = " << z << "\n";
            }
        }
    } else {
        if (x > z) {
            std::cout << "z = " << z << "\n";
            std::cout << "x = " << x << "\n";
            std::cout << "y = " << y << "\n";
        } else {
            std::cout << "x = " << x << "\n";

            if (y > z) {
                std::cout << "z = " << z << "\n";
                std::cout << "y = " << y << "\n";
            } else {
                std::cout << "y = " << y << "\n";
                std::cout << "z = " << z << "\n";
            }
        }
    }

    return 0;
}
<|endoftext|>