<commit_before>/*
* Copyright (C) 2008-2011 J-P Nurmi <jpnurmi@gmail.com>
* Copyright (C) 2010-2011 SmokeX <smokexjc@gmail.com>
* Copyright (C) 2012 Mark Johnson <marknotgeorge@googlemail.com>
*
* 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.
*/

/*
  Parts of this code come from Konversation and are copyrighted to:
  Copyright (C) 2002 Dario Abatianni <eisfuchs@tigress.com>
  Copyright (C) 2004 Peter Simonsson <psn@linux.se>
  Copyright (C) 2006-2008 Eike Hein <hein@kde.org>
  Copyright (C) 2004-2009 Eli Mackenzie <argonel@gmail.com>
*/

#include "ircutil.h"
#include <QString>
#include <QRegExp>
#include <QStringList>

/*!
    \file ircutil.h
    \brief #include <IrcUtil>
 */

/*!
    \class IrcUtil ircutil.h <IrcUtil>
    \ingroup utility
    \brief The IrcUtil class provides miscellaneous utility functions.
 */

static QRegExp URL_PATTERN(QLatin1String("((www\\.(?!\\.)|(ssh|fish|irc|amarok|(f|sf|ht)tp(|s))://)(\\.?[\\d\\w/,\\':~\\^\\?=;#@\\-\\+\\%\\*\\{\\}\\!\\(\\)\\[\\]]|&)+)|""([-.\\d\\w]+@[-.\\d\\w]{2,}\\.[\\w]{2,})"), Qt::CaseInsensitive);

/*!
    Converts \a message to HTML. This function parses the
    message and replaces IRC-style formatting like colors,
    bold and underline to the corresponding HTML formatting.
    Furthermore, this function detects URLs and replaces
    them with appropriate HTML hyperlinks.
*/
QString IrcUtil::messageToHtml(const QString& message)
{
    QString processed = message;
    processed.replace(QLatin1Char('&'), QLatin1String("&"));
    processed.replace(QLatin1Char('<'), QLatin1String("<"));
    processed.replace(QLatin1Char('>'), QLatin1String(">"));
    processed.replace(QLatin1Char('"'), QLatin1String("""));
    processed.replace(QLatin1Char('\''), QLatin1String("'"));
    processed.replace(QLatin1Char('\t'), QLatin1String(" "));

    enum
    {
        None            = 0x0,
        Bold            = 0x1,
        Color           = 0x2,
        Italic          = 0x4,
        StrikeThrough   = 0x8,
        Underline       = 0x10,
        Inverse         = 0x20
    };
    int state = None;

    // Set default colours - MJ
    QString forecolour = "black";
    QString backcolour = "transparent";

    int pos = 0;
    bool parseColor = false;
    while (pos < processed.size())
    {
        if (parseColor)
        {
            int len = 0;
            // If the first character is a digit, we have a valid colour tag. - MJ
            if (processed.at(pos).isDigit())
            {
                ++len;
                // Find the first comma (,). If it's in the right place, we have
                // a foreground and background colour. -MJ
                int comma = processed.indexOf(QLatin1Char(','), pos) - pos;
                if (comma == 1 || comma == 2)
                    len = comma + 1;
                int index = pos + len;
                // Grab the next 1 or 2 characters if they are digits - they form
                // part of the colour tag. - MJ
                if (index < processed.size() && processed.at(index).isDigit())
                {
                    ++len;
                    ++index;
                    if ((index) < processed.size() && processed.at(index).isDigit())
                        ++len;

                }
            }

            bool foreok = false;
            bool backok = false;
            int forecode = 1;
            int backcode = 0;

            // Extract the colour tag. - MJ
            QString colourString = processed.mid(pos, len);

            // Split the colour tag on the comma, if there is one, into foreground
            // and background colour strings. - MJ
            QStringList colorStringList = colourString.split(QLatin1Char(','), QString::SkipEmptyParts);

            // Convert the colour strings into integer codes - MJ
            if (!colorStringList[0].isEmpty())
                forecode = colorStringList[0].toInt(&foreok);
            if (colorStringList.count() > 1 && !colorStringList[1].isEmpty())
                backcode = colorStringList[1].toInt(&backok);

            // If the colour strings converted successfully, turn them into
            // HTML colour names. - MJ.
            if (foreok)
            {
                processed.remove(pos, len);
                forecolour = colorCodeToName(forecode);
                if (backok)
                    backcolour = colorCodeToName(backcode);
            }

            // Add the colour names to the message string - MJ
            processed = processed.arg(forecolour);
            processed = processed.arg(backcolour);
            len = forecolour.length() + backcolour.length();
            if (pos >= processed.size())
                break;
            parseColor = false;
        }

        QString replacement;
        switch (processed.at(pos).unicode())
        {
        case '\x02': // bold
            if (state & Bold)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Bold;
            break;

        case '\x03': // color - modified to include a background-color tag. - MJ
            if (state & Color)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Color;
            parseColor = state & Color;
            break;

        //case '\x09': // italic
        case '\x1d': // italic
            if (state & Italic)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Italic;
            break;

        case '\x13': // strike-through
            if (state & StrikeThrough)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= StrikeThrough;
            break;

        case '\x15': // underline
        case '\x1f': // underline
            if (state & Underline)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Underline;
            break;

        case '\x16': // inverse
            if (state & Inverse)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Inverse;
            break;

        case '\x0f': // none
            replacement = QLatin1String("");
            state = None;
            break;

        default:
            break;
        }

        if (!replacement.isNull())
        {
            processed.replace(pos, 1, replacement);
            pos += replacement.length();
        }
        else
        {
            ++pos;
        }
    }

    pos = 0;
    while ((pos = URL_PATTERN.indexIn(processed, pos)) >= 0)
    {
        int len = URL_PATTERN.matchedLength();
        QString href = processed.mid(pos, len);

        // Don't consider trailing > as part of the link.
        QString append;
        if (href.endsWith(QLatin1String(">")))
        {
            append.append(href.right(4));
            href.chop(4);
        }

        // Don't consider trailing comma or semi-colon as part of the link.
        if (href.endsWith(QLatin1Char(',')) || href.endsWith(QLatin1Char(';')))
        {
            append.append(href.right(1));
            href.chop(1);
        }

        // Don't consider trailing closing parenthesis part of the link when
        // there's an opening parenthesis preceding in the beginning of the
        // URL or there is no opening parenthesis in the URL at all.
        if (pos > 0 && href.endsWith(QLatin1Char(')'))
            && (processed.at(pos-1) == QLatin1Char('(')
            || !href.contains(QLatin1Char('('))))
        {
            append.prepend(href.right(1));
            href.chop(1);
        }

        // Qt doesn't support (?<=pattern) so we do it here
        if (pos > 0 && processed.at(pos-1).isLetterOrNumber())
        {
            pos++;
            continue;
        }

        QString protocol;
        if (URL_PATTERN.cap(1).startsWith(QLatin1String("www."), Qt::CaseInsensitive))
            protocol = QLatin1String("http://");
        else if (URL_PATTERN.cap(1).isEmpty())
            protocol = QLatin1String("mailto:");

        QString source = href;
        source.replace(QLatin1String("&"), QLatin1String("&"));

        QString link = QString(QLatin1String("%3")).arg(protocol, source, href) + append;
        processed.replace(pos, len, link);
        pos += link.length();
    }

    return processed;
}

/*!
    Converts a color \a code to a color name.
*/
QString IrcUtil::colorCodeToName(int code)
{
    switch (code)
    {
    case 0:  return QLatin1String("white");
    case 1:  return QLatin1String("black");
    case 2:  return QLatin1String("navy");
    case 3:  return QLatin1String("green");
    case 4:  return QLatin1String("red");
    case 5:  return QLatin1String("maroon");
    case 6:  return QLatin1String("purple");
    case 7:  return QLatin1String("orange");
    case 8:  return QLatin1String("yellow");
    case 9:  return QLatin1String("lime");
    case 10: return QLatin1String("darkcyan");
    case 11: return QLatin1String("cyan");
    case 12: return QLatin1String("blue");
    case 13: return QLatin1String("magenta");
    case 14: return QLatin1String("gray");
    case 15: return QLatin1String("lightgray");
    default: return QLatin1String("black");
    }
}

<commit_msg>IrcUtil: fix color parsing not to crash due to invalid formatting<commit_after>/*
* Copyright (C) 2008-2011 J-P Nurmi <jpnurmi@gmail.com>
* Copyright (C) 2010-2011 SmokeX <smokexjc@gmail.com>
* Copyright (C) 2012 Mark Johnson <marknotgeorge@googlemail.com>
*
* 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.
*/

/*
  Parts of this code come from Konversation and are copyrighted to:
  Copyright (C) 2002 Dario Abatianni <eisfuchs@tigress.com>
  Copyright (C) 2004 Peter Simonsson <psn@linux.se>
  Copyright (C) 2006-2008 Eike Hein <hein@kde.org>
  Copyright (C) 2004-2009 Eli Mackenzie <argonel@gmail.com>
*/

#include "ircutil.h"
#include <QString>
#include <QRegExp>
#include <QStringList>

/*!
    \file ircutil.h
    \brief #include <IrcUtil>
 */

/*!
    \class IrcUtil ircutil.h <IrcUtil>
    \ingroup utility
    \brief The IrcUtil class provides miscellaneous utility functions.
 */

static QRegExp URL_PATTERN(QLatin1String("((www\\.(?!\\.)|(ssh|fish|irc|amarok|(f|sf|ht)tp(|s))://)(\\.?[\\d\\w/,\\':~\\^\\?=;#@\\-\\+\\%\\*\\{\\}\\!\\(\\)\\[\\]]|&)+)|""([-.\\d\\w]+@[-.\\d\\w]{2,}\\.[\\w]{2,})"), Qt::CaseInsensitive);

/*!
    Converts \a message to HTML. This function parses the
    message and replaces IRC-style formatting like colors,
    bold and underline to the corresponding HTML formatting.
    Furthermore, this function detects URLs and replaces
    them with appropriate HTML hyperlinks.
*/
QString IrcUtil::messageToHtml(const QString& message)
{
    QString processed = message;
    processed.replace(QLatin1Char('&'), QLatin1String("&"));
    processed.replace(QLatin1Char('<'), QLatin1String("<"));
    processed.replace(QLatin1Char('>'), QLatin1String(">"));
    processed.replace(QLatin1Char('"'), QLatin1String("""));
    processed.replace(QLatin1Char('\''), QLatin1String("'"));
    processed.replace(QLatin1Char('\t'), QLatin1String(" "));

    enum
    {
        None            = 0x0,
        Bold            = 0x1,
        Color           = 0x2,
        Italic          = 0x4,
        StrikeThrough   = 0x8,
        Underline       = 0x10,
        Inverse         = 0x20
    };
    int state = None;

    int pos = 0;
    bool parseColor = false;
    while (pos < processed.size())
    {
        if (parseColor)
        {
            // fg(,bg)
            QRegExp rx(QLatin1String("(\\d{1,2})(?:,(\\d{1,2}))?"));
            int idx = rx.indexIn(processed, pos);
            if (idx == pos)
            {
                bool ok = false;
                QStringList styles;
                processed.remove(idx, rx.matchedLength());

                // foreground
                int code = rx.cap(1).toInt(&ok);
                if (ok)
                    styles += QString(QLatin1String("color:%1")).arg(colorCodeToName(code));

                // background
                code = rx.cap(2).toInt(&ok);
                if (ok)
                    styles += QString(QLatin1String("background-color:%1")).arg(colorCodeToName(code));

                processed = processed.arg(styles.join(QLatin1String(";")));
            }
            parseColor = false;
            continue;
        }

        QString replacement;
        switch (processed.at(pos).unicode())
        {
        case '\x02': // bold
            if (state & Bold)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Bold;
            break;

        case '\x03': // color
            if (state & Color)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Color;
            parseColor = state & Color;
            break;

        //case '\x09': // italic
        case '\x1d': // italic
            if (state & Italic)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Italic;
            break;

        case '\x13': // strike-through
            if (state & StrikeThrough)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= StrikeThrough;
            break;

        case '\x15': // underline
        case '\x1f': // underline
            if (state & Underline)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Underline;
            break;

        case '\x16': // inverse
            if (state & Inverse)
                replacement = QLatin1String("");
            else
                replacement = QLatin1String("");
            state ^= Inverse;
            break;

        case '\x0f': // none
            replacement = QLatin1String("");
            state = None;
            break;

        default:
            break;
        }

        if (!replacement.isNull())
        {
            processed.replace(pos, 1, replacement);
            pos += replacement.length();
        }
        else
        {
            ++pos;
        }
    }

    pos = 0;
    while ((pos = URL_PATTERN.indexIn(processed, pos)) >= 0)
    {
        int len = URL_PATTERN.matchedLength();
        QString href = processed.mid(pos, len);

        // Don't consider trailing > as part of the link.
        QString append;
        if (href.endsWith(QLatin1String(">")))
        {
            append.append(href.right(4));
            href.chop(4);
        }

        // Don't consider trailing comma or semi-colon as part of the link.
        if (href.endsWith(QLatin1Char(',')) || href.endsWith(QLatin1Char(';')))
        {
            append.append(href.right(1));
            href.chop(1);
        }

        // Don't consider trailing closing parenthesis part of the link when
        // there's an opening parenthesis preceding in the beginning of the
        // URL or there is no opening parenthesis in the URL at all.
        if (pos > 0 && href.endsWith(QLatin1Char(')'))
            && (processed.at(pos-1) == QLatin1Char('(')
            || !href.contains(QLatin1Char('('))))
        {
            append.prepend(href.right(1));
            href.chop(1);
        }

        // Qt doesn't support (?<=pattern) so we do it here
        if (pos > 0 && processed.at(pos-1).isLetterOrNumber())
        {
            pos++;
            continue;
        }

        QString protocol;
        if (URL_PATTERN.cap(1).startsWith(QLatin1String("www."), Qt::CaseInsensitive))
            protocol = QLatin1String("http://");
        else if (URL_PATTERN.cap(1).isEmpty())
            protocol = QLatin1String("mailto:");

        QString source = href;
        source.replace(QLatin1String("&"), QLatin1String("&"));

        QString link = QString(QLatin1String("%3")).arg(protocol, source, href) + append;
        processed.replace(pos, len, link);
        pos += link.length();
    }

    return processed;
}

/*!
    Converts a color \a code to a color name.
*/
QString IrcUtil::colorCodeToName(int code)
{
    switch (code)
    {
    case 0:  return QLatin1String("white");
    case 1:  return QLatin1String("black");
    case 2:  return QLatin1String("navy");
    case 3:  return QLatin1String("green");
    case 4:  return QLatin1String("red");
    case 5:  return QLatin1String("maroon");
    case 6:  return QLatin1String("purple");
    case 7:  return QLatin1String("orange");
    case 8:  return QLatin1String("yellow");
    case 9:  return QLatin1String("lime");
    case 10: return QLatin1String("darkcyan");
    case 11: return QLatin1String("cyan");
    case 12: return QLatin1String("blue");
    case 13: return QLatin1String("magenta");
    case 14: return QLatin1String("gray");
    case 15: return QLatin1String("lightgray");
    default: return QLatin1String("black");
    }
}

<|endoftext|>


<commit_before>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <cstring>
#include <string>
#include <map>

using namespace std;

typedef map<string,string> CmdEntries;

CmdEntries commands;
CmdEntries files;

int fileline=0;
void GetBf(char* buf, int size, FILE*f)
{
  if (!fgets(buf,2048,f))
  {
    *buf = '\0';
    if (!feof(f))
    {
      printf("Error reading, bailing out.\n");
      exit(-1);
    }
  }

  fileline++;
  if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
  char* ptr=buf;
  while (*ptr != '\0')
  {
    if (*ptr == ':') *ptr = ' ';
    ptr++;
  }
}

void ProcessFile(char* fname)
{
  fprintf(stderr,"\tFILE %s\n",fname);
  FILE*f = fopen(fname,"r");
  if (!f) return;
  int prevline = fileline;
  fileline = 0;
  char buf[2048];
  while (!feof(f))
  {
    GetBf(buf,2048,f);
    if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';

    //*CMD Sin, Cos, Tan --- trigonometric functions
    if (!strncmp(buf,"*CMD",4))
    {
      char* description=buf;
      while (*description != '\0' && *description != '-') description++;
      if (*description == '\0') continue;
      while (*description == '-') description++;
      while (*description == ' ') description++;

      char* command = &buf[5];
      for(;;)
      {
        char* end = command;
        while (*end != ',' && *end != ' ') end++;
        char cmd[256];
        memset(cmd,0,255);
        memcpy(cmd,command,end-command);
//        cmd[end-command] = '\0';

        commands[cmd] = description;
        files[cmd] = fname;

//printf("COMMAND [%s], description [%s]\n",cmd,description);
        if (*end == ' ') break;
        end++;
        if (*end == ' ') end++;
        command = end;
      }
    }
    else if (!strncmp(buf,"*CALL",5))
    {
      while (buf[0] != '\t')
        GetBf(buf,2048,f);
      char cmd[256];
      while (buf[0] == '\t')
      {
        if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
        char* ptr = &buf[1];
        while (isalnum(*ptr) || *ptr == '\'') ptr++;
        memset(cmd,0,255);
        memcpy(cmd,&buf[1],ptr-(&buf[1]));

        if (cmd[0] && strncmp(&buf[1],"In>",3) && strncmp(&buf[1],"Out>",4) && isupper(buf[1]))
        {
          CmdEntries::const_iterator iter = commands.find(cmd);
          const char* desc = "";
          if (iter != commands.end())
          {
            desc = iter->second.c_str();
          }
          else
          {
            fprintf(stderr,"WARNING: function %s does not have a short description (%s:%d)\n",cmd,fname,fileline);
          }
          printf(":%s:%s:%s:\n",cmd,&buf[1],desc);
          commands[cmd] = "";
        }
        GetBf(buf,2048,f);
        while (buf[0] == '\0') GetBf(buf,2048,f);
      }
      if (buf[0] == ' ')
      {
        fprintf(stderr,"WARNING: spaces might have been used in stead of tabs (%s, %s:%d)\n",cmd,fname,fileline);
      }
    }
    else if (!strncmp(buf,"*INCLUDE",8))
    {
      char*fn = &buf[8];
      while (*fn == ' ') fn++;
      char fullname[512];
      snprintf(fullname,512,"%s.txt",fn);
//DEBUG printf("FILE %s\n",fullname);
      ProcessFile(fullname);

    }
  }
  fclose(f);
  fileline = prevline;
}

int main(int argc, char** argv)
{
  int i;
  for (i=1;i<argc;i++)
  {
    fprintf(stderr,"BOOK %s\n",argv[i]);
    ProcessFile(argv[i]);
  }
  CmdEntries::const_iterator iter = commands.begin();
  while (iter != commands.end())
  {
    if (iter->second.c_str()[0])
    {
      CmdEntries::const_iterator fiter = files.find(iter->first.c_str());
      if (fiter != files.end())
        fprintf(stderr,"WARNING: no call sequences for function %s (%s)\n",iter->first.c_str(),fiter->second.c_str());
      else
        fprintf(stderr,"WARNING: no call sequences for function %s\n",iter->first.c_str());
    }
    iter++;
  }

}
<commit_msg>fixed buffer overrun<commit_after>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <cstring>
#include <string>
#include <map>

using namespace std;

typedef map<string,string> CmdEntries;

CmdEntries commands;
CmdEntries files;

int fileline=0;
void GetBf(char* buf, int size, FILE*f)
{
  if (!fgets(buf,2048,f))
  {
    *buf = '\0';
    if (!feof(f))
    {
      printf("Error reading, bailing out.\n");
      exit(-1);
    }
  }

  fileline++;
  const std::size_t n = std::strlen(buf);
  if (n && buf[n - 1] == '\n')
      buf[n] = '\0';
  char* ptr=buf;
  while (*ptr != '\0')
  {
    if (*ptr == ':') *ptr = ' ';
    ptr++;
  }
}

void ProcessFile(char* fname)
{
  fprintf(stderr,"\tFILE %s\n",fname);
  FILE*f = fopen(fname,"r");
  if (!f) return;
  int prevline = fileline;
  fileline = 0;
  char buf[2048];
  while (!feof(f))
  {
    GetBf(buf,2048,f);
    const std::size_t n = std::strlen(buf);
    if (n && buf[n - 1] == '\n')
        buf[n - 1] = '\0';

    //*CMD Sin, Cos, Tan --- trigonometric functions
    if (!strncmp(buf,"*CMD",4))
    {
      char* description=buf;
      while (*description != '\0' && *description != '-') description++;
      if (*description == '\0') continue;
      while (*description == '-') description++;
      while (*description == ' ') description++;

      char* command = &buf[5];
      for(;;)
      {
        char* end = command;
        while (*end != ',' && *end != ' ') end++;
        char cmd[256];
        memset(cmd,0,255);
        memcpy(cmd,command,end-command);
//        cmd[end-command] = '\0';

        commands[cmd] = description;
        files[cmd] = fname;

//printf("COMMAND [%s], description [%s]\n",cmd,description);
        if (*end == ' ') break;
        end++;
        if (*end == ' ') end++;
        command = end;
      }
    }
    else if (!strncmp(buf,"*CALL",5))
    {
      while (buf[0] != '\t')
        GetBf(buf,2048,f);
      char cmd[256];
      while (buf[0] == '\t')
      {
        if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
        char* ptr = &buf[1];
        while (isalnum(*ptr) || *ptr == '\'') ptr++;
        memset(cmd,0,255);
        memcpy(cmd,&buf[1],ptr-(&buf[1]));

        if (cmd[0] && strncmp(&buf[1],"In>",3) && strncmp(&buf[1],"Out>",4) && isupper(buf[1]))
        {
          CmdEntries::const_iterator iter = commands.find(cmd);
          const char* desc = "";
          if (iter != commands.end())
          {
            desc = iter->second.c_str();
          }
          else
          {
            fprintf(stderr,"WARNING: function %s does not have a short description (%s:%d)\n",cmd,fname,fileline);
          }
          printf(":%s:%s:%s:\n",cmd,&buf[1],desc);
          commands[cmd] = "";
        }
        GetBf(buf,2048,f);
        while (buf[0] == '\0') GetBf(buf,2048,f);
      }
      if (buf[0] == ' ')
      {
        fprintf(stderr,"WARNING: spaces might have been used in stead of tabs (%s, %s:%d)\n",cmd,fname,fileline);
      }
    }
    else if (!strncmp(buf,"*INCLUDE",8))
    {
      char*fn = &buf[8];
      while (*fn == ' ') fn++;
      char fullname[512];
      snprintf(fullname,512,"%s.txt",fn);
//DEBUG printf("FILE %s\n",fullname);
      ProcessFile(fullname);

    }
  }
  fclose(f);
  fileline = prevline;
}

int main(int argc, char** argv)
{
  int i;
  for (i=1;i<argc;i++)
  {
    fprintf(stderr,"BOOK %s\n",argv[i]);
    ProcessFile(argv[i]);
  }
  CmdEntries::const_iterator iter = commands.begin();
  while (iter != commands.end())
  {
    if (iter->second.c_str()[0])
    {
      CmdEntries::const_iterator fiter = files.find(iter->first.c_str());
      if (fiter != files.end())
        fprintf(stderr,"WARNING: no call sequences for function %s (%s)\n",iter->first.c_str(),fiter->second.c_str());
      else
        fprintf(stderr,"WARNING: no call sequences for function %s\n",iter->first.c_str());
    }
    iter++;
  }

}
<|endoftext|>


<commit_before>/** \file   Subfields.cc
 *  \brief  Implementation of the Subfields class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2014 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Subfields.h"
#include <stdexcept>
#include "Compiler.h"
#include "util.h"

Subfields::Subfields(const std::string &field_data) {
    if (field_data.size() < 3) {
        indicator1_ = indicator2_ = '\0';
        return;
    }

    std::string::const_iterator ch(field_data.begin());
    indicator1_ = *ch++;
    indicator2_ = *ch++;

    while (ch != field_data.end()) {
        if (*ch != '\x1F')
            std::runtime_error(
                    "in Subfields::Subfields(const std::string &): expected subfield code delimiter not found! "
                            "Found " + std::string(1, *ch) + " in " + field_data + " indicators: "
                    + std::string(1, indicator1_) + ", " + std::string(1, indicator2_) + "! " + field_data);

        ++ch;
        if (ch == field_data.end())
            std::runtime_error(
                    "in Subfields::Subfields(const std::string &): unexpected subfield data end while expecting "
                            "a subfield code! " + field_data);
        const char subfield_code = *ch++;

        std::string subfield_data;
        while (ch != field_data.end() and *ch != '\x1F')
            subfield_data += *ch++;
        if (not subfield_data.empty())
            subfields_.emplace_back(subfield_code, subfield_data);
    }

    std::sort(begin(), end(), SubfieldCodeLessThan());
}

bool Subfields::hasSubfieldWithValue(const char subfield_code, const std::string &value) const {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    for (/* empty */; code_and_value != end() && code_and_value->code_ == subfield_code; ++code_and_value) {
        if (code_and_value->value_ == value)
            return true;
    }
    return false;
}

std::string Subfields::getFirstSubfieldValue(const char subfield_code) const {
    const auto begin_end(getIterators(subfield_code));
    if (begin_end.first == begin_end.second)
        return "";
    return begin_end.first->value_;
}

void Subfields::addSubfield(const char subfield_code, const std::string &subfield_data) {
    auto insert(begin());
    for (/* empty */; insert != end() && insert->code_ <= subfield_code; ++insert);
    subfields_.emplace(insert, subfield_code, subfield_data);
}

void Subfields::replace(const char subfield_code, const std::string &old_value, const std::string &new_value) {
    bool found(false);

    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value) {
        if (code_and_value->value_ == old_value) {
            found = true;
            code_and_value->value_ = new_value;
        }
    }

    if (not found)
        throw std::runtime_error(
                "Subfields::replace: tried to replace \"" + old_value + "\" with \"" + new_value + "\" in subfield '"
                + subfield_code + "' but did not find the original value!");
}

void Subfields::erase(const char subfield_code) {
    const auto begin_end(getIterators(subfield_code));
    subfields_.erase(begin_end.first, begin_end.second);
}

void Subfields::erase(const char subfield_code, const std::string &value) {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    while (code_and_value != end() and code_and_value->code_ == subfield_code) {
        if (code_and_value->value_ == value)
            code_and_value = subfields_.erase(code_and_value);
        else
            ++code_and_value;
    }
}

void Subfields::moveSubfield(const char from_subfield_code, const char to_subfield_code) {
    erase(to_subfield_code);
    std::vector <std::string> values;
    extractSubfields(from_subfield_code, &values);
    for (auto value : values)
        subfields_.emplace_back(to_subfield_code, value);
    erase(from_subfield_code);
    std::sort(begin(), end(), SubfieldCodeLessThan());
}

size_t Subfields::extractSubfields(const std::string &subfield_codes,
                                   std::vector <std::string> *const subfield_values) const {
    for (char subfield_code : subfield_codes) {
        extractSubfields(subfield_code, subfield_values);
    }
    return subfield_values->size();
}

void Subfields::extractSubfields(const char subfield_code, std::vector <std::string> *const subfield_values) const {
    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value)
        subfield_values->emplace_back(code_and_value->value_);
}

std::string Subfields::toString() const {
    std::string as_string;

    as_string += indicator1_;
    as_string += indicator2_;

    for (const_iterator code_and_value(cbegin()); code_and_value != cend(); ++code_and_value) {
        as_string += '\x1F';
        as_string += code_and_value->code_;
        as_string += code_and_value->value_;
    }

    return as_string;
}
<commit_msg>Cosmetic.<commit_after>/** \file   Subfields.cc
 *  \brief  Implementation of the Subfields class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2014,2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "Subfields.h"
#include <stdexcept>
#include "Compiler.h"
#include "util.h"

Subfields::Subfields(const std::string &field_data) {
    if (field_data.size() < 3) {
        indicator1_ = indicator2_ = '\0';
        return;
    }

    std::string::const_iterator ch(field_data.begin());
    indicator1_ = *ch++;
    indicator2_ = *ch++;

    while (ch != field_data.end()) {
        if (*ch != '\x1F')
            std::runtime_error(
                "in Subfields::Subfields(const std::string &): expected subfield code delimiter not found! "
                "Found " + std::string(1, *ch) + " in " + field_data + " indicators: "
                + std::string(1, indicator1_) + ", " + std::string(1, indicator2_) + "! " + field_data);

        ++ch;
        if (ch == field_data.end())
            std::runtime_error(
                "in Subfields::Subfields(const std::string &): unexpected subfield data end while expecting "
                "a subfield code! " + field_data);
        const char subfield_code(*ch++);

        std::string subfield_data;
        while (ch != field_data.end() and *ch != '\x1F')
            subfield_data += *ch++;
        if (not subfield_data.empty())
            subfields_.emplace_back(subfield_code, subfield_data);
    }

    std::sort(begin(), end(), SubfieldCodeLessThan());
}

bool Subfields::hasSubfieldWithValue(const char subfield_code, const std::string &value) const {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    for (/* empty */; code_and_value != end() && code_and_value->code_ == subfield_code; ++code_and_value) {
        if (code_and_value->value_ == value)
            return true;
    }
    return false;
}

std::string Subfields::getFirstSubfieldValue(const char subfield_code) const {
    const auto begin_end(getIterators(subfield_code));
    if (begin_end.first == begin_end.second)
        return "";
    return begin_end.first->value_;
}

void Subfields::addSubfield(const char subfield_code, const std::string &subfield_data) {
    auto insert(begin());
    for (/* empty */; insert != end() && insert->code_ <= subfield_code; ++insert);
    subfields_.emplace(insert, subfield_code, subfield_data);
}

void Subfields::replace(const char subfield_code, const std::string &old_value, const std::string &new_value) {
    bool found(false);

    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value) {
        if (code_and_value->value_ == old_value) {
            found = true;
            code_and_value->value_ = new_value;
        }
    }

    if (not found)
        throw std::runtime_error(
                "Subfields::replace: tried to replace \"" + old_value + "\" with \"" + new_value + "\" in subfield '"
                + subfield_code + "' but did not find the original value!");
}

void Subfields::erase(const char subfield_code) {
    const auto begin_end(getIterators(subfield_code));
    subfields_.erase(begin_end.first, begin_end.second);
}

void Subfields::erase(const char subfield_code, const std::string &value) {
    auto code_and_value(std::find_if(begin(), end(), CompareSubfieldCode(subfield_code)));
    while (code_and_value != end() and code_and_value->code_ == subfield_code) {
        if (code_and_value->value_ == value)
            code_and_value = subfields_.erase(code_and_value);
        else
            ++code_and_value;
    }
}

void Subfields::moveSubfield(const char from_subfield_code, const char to_subfield_code) {
    erase(to_subfield_code);
    std::vector <std::string> values;
    extractSubfields(from_subfield_code, &values);
    for (auto value : values)
        subfields_.emplace_back(to_subfield_code, value);
    erase(from_subfield_code);
    std::sort(begin(), end(), SubfieldCodeLessThan());
}

size_t Subfields::extractSubfields(const std::string &subfield_codes,
                                   std::vector <std::string> *const subfield_values) const {
    for (char subfield_code : subfield_codes) {
        extractSubfields(subfield_code, subfield_values);
    }
    return subfield_values->size();
}

void Subfields::extractSubfields(const char subfield_code, std::vector <std::string> *const subfield_values) const {
    const auto begin_end(getIterators(subfield_code));
    for (auto code_and_value(begin_end.first); code_and_value != begin_end.second; ++code_and_value)
        subfield_values->emplace_back(code_and_value->value_);
}

std::string Subfields::toString() const {
    std::string as_string;

    as_string += indicator1_;
    as_string += indicator2_;

    for (const_iterator code_and_value(cbegin()); code_and_value != cend(); ++code_and_value) {
        as_string += '\x1F';
        as_string += code_and_value->code_;
        as_string += code_and_value->value_;
    }

    return as_string;
}
<|endoftext|>


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

#include "GrVkImage.h"
#include "GrGpuResourcePriv.h"
#include "GrVkGpu.h"
#include "GrVkMemory.h"
#include "GrVkTexture.h"
#include "GrVkUtil.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) {
    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
        return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_TRANSFER_BIT;
    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
        return VK_PIPELINE_STAGE_HOST_BIT;
    } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    }

    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
    return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}

VkAccessFlags GrVkImage::LayoutToSrcAccessMask(const VkImageLayout layout) {
    // Currently we assume we will never being doing any explict shader writes (this doesn't include
    // color attachment or depth/stencil writes). So we will ignore the
    // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.

    // We can only directly access the host memory if we are in preinitialized or general layout,
    // and the image is linear.
    // TODO: Add check for linear here so we are not always adding host to general, and we should
    //       only be in preinitialized if we are linear
    VkAccessFlags flags = 0;
    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
                VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
                VK_ACCESS_TRANSFER_WRITE_BIT |
                VK_ACCESS_TRANSFER_READ_BIT |
                VK_ACCESS_SHADER_READ_BIT |
                VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
        flags = VK_ACCESS_HOST_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
        flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
        flags = VK_ACCESS_TRANSFER_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
        flags = VK_ACCESS_TRANSFER_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
        flags = VK_ACCESS_SHADER_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
        flags = 0;
    }
    return flags;
}

VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format) {
    switch (format) {
        case VK_FORMAT_S8_UINT:
            return VK_IMAGE_ASPECT_STENCIL_BIT;
        case VK_FORMAT_D24_UNORM_S8_UINT: // fallthrough
        case VK_FORMAT_D32_SFLOAT_S8_UINT:
            return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
        default:
            SkASSERT(GrVkFormatIsSupported(format));
            return VK_IMAGE_ASPECT_COLOR_BIT;
    }
}

void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout,
                               VkAccessFlags dstAccessMask,
                               VkPipelineStageFlags dstStageMask,
                               bool byRegion, bool releaseFamilyQueue) {
    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
             VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout);
    VkImageLayout currentLayout = this->currentLayout();

    if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInitialQueueFamily &&
        newLayout == currentLayout) {
        // We never transfered the image to this queue and we are releasing it so don't do anything.
        return;
    }

    // If the old and new layout are the same and the layout is a read only layout, there is no need
    // to put in a barrier.
    if (newLayout == currentLayout &&
        !releaseFamilyQueue &&
        (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout ||
         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout ||
         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) {
        return;
    }

    VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(currentLayout);
    VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(currentLayout);

    VkImageAspectFlags aspectFlags = vk_format_to_aspect_flags(fInfo.fFormat);

    uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    if (fInfo.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
        gpu->queueIndex() != fInfo.fCurrentQueueFamily) {
        // The image still is owned by its original queue family and we need to transfer it into
        // ours.
        SkASSERT(!releaseFamilyQueue);
        SkASSERT(fInfo.fCurrentQueueFamily == fInitialQueueFamily);

        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
        dstQueueFamilyIndex = gpu->queueIndex();
        fInfo.fCurrentQueueFamily = gpu->queueIndex();
    } else if (releaseFamilyQueue) {
        // We are releasing the image so we must transfer the image back to its original queue
        // family.
        SkASSERT(fInfo.fCurrentQueueFamily == gpu->queueIndex());
        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
        dstQueueFamilyIndex = fInitialQueueFamily;
        fInfo.fCurrentQueueFamily = fInitialQueueFamily;
    }

    VkImageMemoryBarrier imageMemoryBarrier = {
        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // sType
        nullptr,                                         // pNext
        srcAccessMask,                                   // outputMask
        dstAccessMask,                                   // inputMask
        currentLayout,                                   // oldLayout
        newLayout,                                       // newLayout
        srcQueueFamilyIndex,                             // srcQueueFamilyIndex
        dstQueueFamilyIndex,                             // dstQueueFamilyIndex
        fInfo.fImage,                                    // image
        { aspectFlags, 0, fInfo.fLevelCount, 0, 1 }      // subresourceRange
    };

    gpu->addImageMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion,
                               &imageMemoryBarrier);

    this->updateImageLayout(newLayout);
}

bool GrVkImage::InitImageInfo(const GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo* info) {
    if (0 == imageDesc.fWidth || 0 == imageDesc.fHeight) {
        return false;
    }
    VkImage image = 0;
    GrVkAlloc alloc;

    bool isLinear = VK_IMAGE_TILING_LINEAR == imageDesc.fImageTiling;
    VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
                                           : VK_IMAGE_LAYOUT_UNDEFINED;

    // Create Image
    VkSampleCountFlagBits vkSamples;
    if (!GrSampleCountToVkSampleCount(imageDesc.fSamples, &vkSamples)) {
        return false;
    }

    SkASSERT(VK_IMAGE_TILING_OPTIMAL == imageDesc.fImageTiling ||
             VK_SAMPLE_COUNT_1_BIT == vkSamples);

    const VkImageCreateInfo imageCreateInfo = {
        VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
        nullptr,                                     // pNext
        0,                                           // VkImageCreateFlags
        imageDesc.fImageType,                        // VkImageType
        imageDesc.fFormat,                           // VkFormat
        { imageDesc.fWidth, imageDesc.fHeight, 1 },  // VkExtent3D
        imageDesc.fLevels,                           // mipLevels
        1,                                           // arrayLayers
        vkSamples,                                   // samples
        imageDesc.fImageTiling,                      // VkImageTiling
        imageDesc.fUsageFlags,                       // VkImageUsageFlags
        VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
        0,                                           // queueFamilyCount
        0,                                           // pQueueFamilyIndices
        initialLayout                                // initialLayout
    };

    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateImage(gpu->device(), &imageCreateInfo, nullptr,
                                                        &image));

    if (!GrVkMemory::AllocAndBindImageMemory(gpu, image, isLinear, &alloc)) {
        VK_CALL(gpu, DestroyImage(gpu->device(), image, nullptr));
        return false;
    }

    info->fImage = image;
    info->fAlloc = alloc;
    info->fImageTiling = imageDesc.fImageTiling;
    info->fImageLayout = initialLayout;
    info->fFormat = imageDesc.fFormat;
    info->fLevelCount = imageDesc.fLevels;
    info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
    return true;
}

void GrVkImage::DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo* info) {
    VK_CALL(gpu, DestroyImage(gpu->device(), info->fImage, nullptr));
    bool isLinear = VK_IMAGE_TILING_LINEAR == info->fImageTiling;
    GrVkMemory::FreeImageMemory(gpu, isLinear, info->fAlloc);
}

GrVkImage::~GrVkImage() {
    // should have been released or abandoned first
    SkASSERT(!fResource);
}

void GrVkImage::prepareForPresent(GrVkGpu* gpu) {
    VkImageLayout layout = this->currentLayout();
    if (fInitialQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
        fInitialQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
        if (gpu->vkCaps().supportsSwapchain()) {
            layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        }
    }
    this->setImageLayout(gpu, layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, true);
}

void GrVkImage::releaseImage(GrVkGpu* gpu) {
    if (fInfo.fCurrentQueueFamily != fInitialQueueFamily) {
        // The Vulkan spec is vague on what to put for the dstStageMask here. The spec for image
        // memory barrier says the dstStageMask must not be zero. However, in the spec when it talks
        // about family queue transfers it says the dstStageMask is ignored and should be set to
        // zero. Assuming it really is ignored we set it to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT here
        // since it makes the Vulkan validation layers happy.
        this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                             false, true);
    }
    if (fResource) {
        fResource->removeOwningTexture();
        fResource->unref(gpu);
        fResource = nullptr;
    }
}

void GrVkImage::abandonImage() {
    if (fResource) {
        fResource->removeOwningTexture();
        fResource->unrefAndAbandon();
        fResource = nullptr;
    }
}

void GrVkImage::setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper) {
    SkASSERT(fResource);
    // Forward the release proc on to GrVkImage::Resource
    fResource->setRelease(std::move(releaseHelper));
}

void GrVkImage::Resource::freeGPUData(GrVkGpu* gpu) const {
    this->invokeReleaseProc();
    VK_CALL(gpu, DestroyImage(gpu->device(), fImage, nullptr));
    bool isLinear = (VK_IMAGE_TILING_LINEAR == fImageTiling);
    GrVkMemory::FreeImageMemory(gpu, isLinear, fAlloc);
}

void GrVkImage::Resource::replaceIdleProc(
        GrVkTexture* owner, sk_sp<GrRefCntedCallback> idleCallback) const {
    fOwningTexture = owner;
    fIdleCallback = std::move(idleCallback);
}

void GrVkImage::Resource::removeOwningTexture() const { fOwningTexture = nullptr; }

void GrVkImage::Resource::notifyAddedToCommandBuffer() const { ++fNumCommandBufferOwners; }

void GrVkImage::Resource::notifyRemovedFromCommandBuffer() const {
    SkASSERT(fNumCommandBufferOwners);
    if (--fNumCommandBufferOwners || !fIdleCallback) {
        return;
    }
    if (fOwningTexture) {
        if (fOwningTexture->resourcePriv().hasRefOrPendingIO()) {
            return;
        }
        fOwningTexture->removeIdleProc();
    }
    fIdleCallback.reset();
}

void GrVkImage::BorrowedResource::freeGPUData(GrVkGpu* gpu) const {
    this->invokeReleaseProc();
}

void GrVkImage::BorrowedResource::abandonGPUData() const {
    this->invokeReleaseProc();
}

#if GR_TEST_UTILS
void GrVkImage::setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu) {
    fInfo.fCurrentQueueFamily = gpu->queueIndex();
}
#endif

<commit_msg>Remove read access flags from src of memory barriers.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrVkImage.h"
#include "GrGpuResourcePriv.h"
#include "GrVkGpu.h"
#include "GrVkMemory.h"
#include "GrVkTexture.h"
#include "GrVkUtil.h"

#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)

VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) {
    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
        return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_TRANSFER_BIT;
    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
    } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
        return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
        return VK_PIPELINE_STAGE_HOST_BIT;
    } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    }

    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
    return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}

VkAccessFlags GrVkImage::LayoutToSrcAccessMask(const VkImageLayout layout) {
    // Currently we assume we will never being doing any explict shader writes (this doesn't include
    // color attachment or depth/stencil writes). So we will ignore the
    // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.

    // We can only directly access the host memory if we are in preinitialized or general layout,
    // and the image is linear.
    // TODO: Add check for linear here so we are not always adding host to general, and we should
    //       only be in preinitialized if we are linear
    VkAccessFlags flags = 0;
    if (VK_IMAGE_LAYOUT_GENERAL == layout) {
        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
                VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
                VK_ACCESS_TRANSFER_WRITE_BIT |
                VK_ACCESS_TRANSFER_READ_BIT |
                VK_ACCESS_SHADER_READ_BIT |
                VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
        flags = VK_ACCESS_HOST_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
        flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
    } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
        flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
        flags = VK_ACCESS_TRANSFER_WRITE_BIT;
    } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout ||
               VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
        // There are no writes that need to be made available
        flags = 0;
    }
    return flags;
}

VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format) {
    switch (format) {
        case VK_FORMAT_S8_UINT:
            return VK_IMAGE_ASPECT_STENCIL_BIT;
        case VK_FORMAT_D24_UNORM_S8_UINT: // fallthrough
        case VK_FORMAT_D32_SFLOAT_S8_UINT:
            return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
        default:
            SkASSERT(GrVkFormatIsSupported(format));
            return VK_IMAGE_ASPECT_COLOR_BIT;
    }
}

void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout,
                               VkAccessFlags dstAccessMask,
                               VkPipelineStageFlags dstStageMask,
                               bool byRegion, bool releaseFamilyQueue) {
    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
             VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout);
    VkImageLayout currentLayout = this->currentLayout();

    if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInitialQueueFamily &&
        newLayout == currentLayout) {
        // We never transfered the image to this queue and we are releasing it so don't do anything.
        return;
    }

    // If the old and new layout are the same and the layout is a read only layout, there is no need
    // to put in a barrier.
    if (newLayout == currentLayout &&
        !releaseFamilyQueue &&
        (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout ||
         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout ||
         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) {
        return;
    }

    VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(currentLayout);
    VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(currentLayout);

    VkImageAspectFlags aspectFlags = vk_format_to_aspect_flags(fInfo.fFormat);

    uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    if (fInfo.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
        gpu->queueIndex() != fInfo.fCurrentQueueFamily) {
        // The image still is owned by its original queue family and we need to transfer it into
        // ours.
        SkASSERT(!releaseFamilyQueue);
        SkASSERT(fInfo.fCurrentQueueFamily == fInitialQueueFamily);

        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
        dstQueueFamilyIndex = gpu->queueIndex();
        fInfo.fCurrentQueueFamily = gpu->queueIndex();
    } else if (releaseFamilyQueue) {
        // We are releasing the image so we must transfer the image back to its original queue
        // family.
        SkASSERT(fInfo.fCurrentQueueFamily == gpu->queueIndex());
        srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
        dstQueueFamilyIndex = fInitialQueueFamily;
        fInfo.fCurrentQueueFamily = fInitialQueueFamily;
    }

    VkImageMemoryBarrier imageMemoryBarrier = {
        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // sType
        nullptr,                                         // pNext
        srcAccessMask,                                   // outputMask
        dstAccessMask,                                   // inputMask
        currentLayout,                                   // oldLayout
        newLayout,                                       // newLayout
        srcQueueFamilyIndex,                             // srcQueueFamilyIndex
        dstQueueFamilyIndex,                             // dstQueueFamilyIndex
        fInfo.fImage,                                    // image
        { aspectFlags, 0, fInfo.fLevelCount, 0, 1 }      // subresourceRange
    };

    gpu->addImageMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion,
                               &imageMemoryBarrier);

    this->updateImageLayout(newLayout);
}

bool GrVkImage::InitImageInfo(const GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo* info) {
    if (0 == imageDesc.fWidth || 0 == imageDesc.fHeight) {
        return false;
    }
    VkImage image = 0;
    GrVkAlloc alloc;

    bool isLinear = VK_IMAGE_TILING_LINEAR == imageDesc.fImageTiling;
    VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
                                           : VK_IMAGE_LAYOUT_UNDEFINED;

    // Create Image
    VkSampleCountFlagBits vkSamples;
    if (!GrSampleCountToVkSampleCount(imageDesc.fSamples, &vkSamples)) {
        return false;
    }

    SkASSERT(VK_IMAGE_TILING_OPTIMAL == imageDesc.fImageTiling ||
             VK_SAMPLE_COUNT_1_BIT == vkSamples);

    const VkImageCreateInfo imageCreateInfo = {
        VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
        nullptr,                                     // pNext
        0,                                           // VkImageCreateFlags
        imageDesc.fImageType,                        // VkImageType
        imageDesc.fFormat,                           // VkFormat
        { imageDesc.fWidth, imageDesc.fHeight, 1 },  // VkExtent3D
        imageDesc.fLevels,                           // mipLevels
        1,                                           // arrayLayers
        vkSamples,                                   // samples
        imageDesc.fImageTiling,                      // VkImageTiling
        imageDesc.fUsageFlags,                       // VkImageUsageFlags
        VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
        0,                                           // queueFamilyCount
        0,                                           // pQueueFamilyIndices
        initialLayout                                // initialLayout
    };

    GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateImage(gpu->device(), &imageCreateInfo, nullptr,
                                                        &image));

    if (!GrVkMemory::AllocAndBindImageMemory(gpu, image, isLinear, &alloc)) {
        VK_CALL(gpu, DestroyImage(gpu->device(), image, nullptr));
        return false;
    }

    info->fImage = image;
    info->fAlloc = alloc;
    info->fImageTiling = imageDesc.fImageTiling;
    info->fImageLayout = initialLayout;
    info->fFormat = imageDesc.fFormat;
    info->fLevelCount = imageDesc.fLevels;
    info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
    return true;
}

void GrVkImage::DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo* info) {
    VK_CALL(gpu, DestroyImage(gpu->device(), info->fImage, nullptr));
    bool isLinear = VK_IMAGE_TILING_LINEAR == info->fImageTiling;
    GrVkMemory::FreeImageMemory(gpu, isLinear, info->fAlloc);
}

GrVkImage::~GrVkImage() {
    // should have been released or abandoned first
    SkASSERT(!fResource);
}

void GrVkImage::prepareForPresent(GrVkGpu* gpu) {
    VkImageLayout layout = this->currentLayout();
    if (fInitialQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
        fInitialQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
        if (gpu->vkCaps().supportsSwapchain()) {
            layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        }
    }
    this->setImageLayout(gpu, layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, true);
}

void GrVkImage::releaseImage(GrVkGpu* gpu) {
    if (fInfo.fCurrentQueueFamily != fInitialQueueFamily) {
        // The Vulkan spec is vague on what to put for the dstStageMask here. The spec for image
        // memory barrier says the dstStageMask must not be zero. However, in the spec when it talks
        // about family queue transfers it says the dstStageMask is ignored and should be set to
        // zero. Assuming it really is ignored we set it to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT here
        // since it makes the Vulkan validation layers happy.
        this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                             false, true);
    }
    if (fResource) {
        fResource->removeOwningTexture();
        fResource->unref(gpu);
        fResource = nullptr;
    }
}

void GrVkImage::abandonImage() {
    if (fResource) {
        fResource->removeOwningTexture();
        fResource->unrefAndAbandon();
        fResource = nullptr;
    }
}

void GrVkImage::setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper) {
    SkASSERT(fResource);
    // Forward the release proc on to GrVkImage::Resource
    fResource->setRelease(std::move(releaseHelper));
}

void GrVkImage::Resource::freeGPUData(GrVkGpu* gpu) const {
    this->invokeReleaseProc();
    VK_CALL(gpu, DestroyImage(gpu->device(), fImage, nullptr));
    bool isLinear = (VK_IMAGE_TILING_LINEAR == fImageTiling);
    GrVkMemory::FreeImageMemory(gpu, isLinear, fAlloc);
}

void GrVkImage::Resource::replaceIdleProc(
        GrVkTexture* owner, sk_sp<GrRefCntedCallback> idleCallback) const {
    fOwningTexture = owner;
    fIdleCallback = std::move(idleCallback);
}

void GrVkImage::Resource::removeOwningTexture() const { fOwningTexture = nullptr; }

void GrVkImage::Resource::notifyAddedToCommandBuffer() const { ++fNumCommandBufferOwners; }

void GrVkImage::Resource::notifyRemovedFromCommandBuffer() const {
    SkASSERT(fNumCommandBufferOwners);
    if (--fNumCommandBufferOwners || !fIdleCallback) {
        return;
    }
    if (fOwningTexture) {
        if (fOwningTexture->resourcePriv().hasRefOrPendingIO()) {
            return;
        }
        fOwningTexture->removeIdleProc();
    }
    fIdleCallback.reset();
}

void GrVkImage::BorrowedResource::freeGPUData(GrVkGpu* gpu) const {
    this->invokeReleaseProc();
}

void GrVkImage::BorrowedResource::abandonGPUData() const {
    this->invokeReleaseProc();
}

#if GR_TEST_UTILS
void GrVkImage::setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu) {
    fInfo.fCurrentQueueFamily = gpu->queueIndex();
}
#endif

<|endoftext|>


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

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include <objidl.h>
#include <mlang.h>
#endif

#include "chrome/renderer/render_process.h"

#include "app/surface/transport_dib.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/histogram.h"
#include "base/path_service.h"
#include "base/sys_info.h"
// TODO(jar): DNS calls should be renderer specific, not including browser.
#include "chrome/browser/net/dns_global.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/nacl_types.h"
#include "chrome/renderer/render_view.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_message_utils.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#include "webkit/glue/webkit_glue.h"

#if defined(OS_MACOSX)
#include "base/mac_util.h"
#endif

//-----------------------------------------------------------------------------

RenderProcess::RenderProcess()
    : ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_(
          base::TimeDelta::FromSeconds(5),
          this, &RenderProcess::ClearTransportDIBCache)),
      sequence_number_(0) {
  in_process_plugins_ = InProcessPlugins();
  for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i)
    shared_mem_cache_[i] = NULL;

#if defined(OS_WIN)
  // HACK:  See http://b/issue?id=1024307 for rationale.
  if (GetModuleHandle(L"LPK.DLL") == NULL) {
    // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works
    // when buffering into a EMF buffer for printing.
    typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs);
    GdiInitializeLanguagePack gdi_init_lpk =
        reinterpret_cast<GdiInitializeLanguagePack>(GetProcAddress(
            GetModuleHandle(L"GDI32.DLL"),
            "GdiInitializeLanguagePack"));
    DCHECK(gdi_init_lpk);
    if (gdi_init_lpk) {
      gdi_init_lpk(0);
    }
  }
#endif

  // Out of process dev tools rely upon auto break behavior.
  webkit_glue::SetJavaScriptFlags(
      L"--debugger-auto-break"
      // Enable lazy in-memory profiling.
      L" --prof --prof-lazy --logfile=* --compress-log");

  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kJavaScriptFlags)) {
    webkit_glue::SetJavaScriptFlags(
      command_line.GetSwitchValue(switches::kJavaScriptFlags));
  }

  if (command_line.HasSwitch(switches::kEnableWatchdog)) {
    // TODO(JAR): Need to implement renderer IO msgloop watchdog.
  }

  if (command_line.HasSwitch(switches::kDumpHistogramsOnExit)) {
    StatisticsRecorder::set_dump_on_exit(true);
  }

#ifndef DISABLE_NACL
  if (command_line.HasSwitch(switches::kInternalNaCl))
    RegisterInternalNaClPlugin(RenderProcess::LaunchNaClProcess);
#endif

  if (!command_line.HasSwitch(switches::kDisableByteRangeSupport)) {
    webkit_glue::SetMediaCacheEnabled(true);
  }

#if defined(OS_MACOSX)
  FilePath bundle_path = mac_util::MainAppBundlePath();

  initialized_media_library_ =
     media::InitializeMediaLibrary(bundle_path.Append("Libraries"));
#else
  FilePath module_path;
  initialized_media_library_ =
      PathService::Get(base::DIR_MODULE, &module_path) &&
      media::InitializeMediaLibrary(module_path);

  // TODO(hclam): Add more checks here. Currently this is not used.
  if (CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableOpenMax)) {
    media::InitializeOpenMaxLibrary(module_path);
  }
#endif
}

RenderProcess::~RenderProcess() {
  // TODO(port): Try and limit what we pull in for our non-Win unit test bundle.
#ifndef NDEBUG
  // log important leaked objects
  webkit_glue::CheckForLeaks();
#endif

  GetShutDownEvent()->Signal();
  ClearTransportDIBCache();
}

bool RenderProcess::InProcessPlugins() {
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
#if defined(OS_LINUX)
  // Plugin processes require a UI message loop, and the Linux message loop
  // implementation only allows one UI loop per process.
  if (command_line.HasSwitch(switches::kInProcessPlugins))
    NOTIMPLEMENTED() << ": in process plugins not supported on Linux";
  return command_line.HasSwitch(switches::kInProcessPlugins);
#else
  return command_line.HasSwitch(switches::kInProcessPlugins) ||
         command_line.HasSwitch(switches::kSingleProcess);
#endif
}

bool RenderProcess::LaunchNaClProcess(const char* url,
                                      int imc_fd,
                                      nacl::Handle* imc_handle,
                                      nacl::Handle* nacl_process_handle,
                                      int* nacl_process_id) {
  // TODO(gregoryd): nacl::FileDescriptor will be soon merged with
  // base::FileDescriptor
  nacl::FileDescriptor imc_descriptor;
  base::ProcessHandle nacl_process;
  if (!RenderThread::current()->Send(
    new ViewHostMsg_LaunchNaCl(ASCIIToWide(url),
        imc_fd,
        &imc_descriptor,
        &nacl_process,
        reinterpret_cast<base::ProcessId*>(nacl_process_id)))) {
    return false;
  }
  *imc_handle = nacl::ToNativeHandle(imc_descriptor);
  *nacl_process_handle = nacl_process;
  return true;
}

// -----------------------------------------------------------------------------
// Platform specific code for dealing with bitmap transport...

TransportDIB* RenderProcess::CreateTransportDIB(size_t size) {
#if defined(OS_WIN) || defined(OS_LINUX)
  // Windows and Linux create transport DIBs inside the renderer
  return TransportDIB::Create(size, sequence_number_++);
#elif defined(OS_MACOSX)  // defined(OS_WIN) || defined(OS_LINUX)
  // Mac creates transport DIBs in the browser, so we need to do a sync IPC to
  // get one.  The TransportDIB is cached in the browser.
  TransportDIB::Handle handle;
  IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, true, &handle);
  if (!main_thread()->Send(msg))
    return NULL;
  if (handle.fd < 0)
    return NULL;
  return TransportDIB::Map(handle);
#endif  // defined(OS_MACOSX)
}

void RenderProcess::FreeTransportDIB(TransportDIB* dib) {
  if (!dib)
    return;

#if defined(OS_MACOSX)
  // On Mac we need to tell the browser that it can drop a reference to the
  // shared memory.
  IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id());
  main_thread()->Send(msg);
#endif

  delete dib;
}

// -----------------------------------------------------------------------------

skia::PlatformCanvas* RenderProcess::GetDrawingCanvas(
    TransportDIB** memory, const gfx::Rect& rect) {
  int width = rect.width();
  int height = rect.height();
  const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width());
#if defined(OS_LINUX)
  const size_t max_size = base::SysInfo::MaxSharedMemorySize();
#else
  const size_t max_size = 0;
#endif

  // If the requested size is too big, reduce the height. Ideally we might like
  // to reduce the width as well to make the size reduction more "balanced", but
  // it rarely comes up in practice.
  if ((max_size != 0) && (height * stride > max_size))
    height = max_size / stride;

  const size_t size = height * stride;

  if (!GetTransportDIBFromCache(memory, size)) {
    *memory = CreateTransportDIB(size);
    if (!*memory)
      return false;
  }

  return (*memory)->GetPlatformCanvas(width, height);
}

void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) {
  if (PutSharedMemInCache(mem)) {
    shared_mem_cache_cleaner_.Reset();
    return;
  }

  FreeTransportDIB(mem);
}

bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem,
                                             size_t size) {
  // look for a cached object that is suitable for the requested size.
  for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
    if (shared_mem_cache_[i] &&
        size <= shared_mem_cache_[i]->size()) {
      *mem = shared_mem_cache_[i];
      shared_mem_cache_[i] = NULL;
      return true;
    }
  }

  return false;
}

int RenderProcess::FindFreeCacheSlot(size_t size) {
  // simple algorithm:
  //  - look for an empty slot to store mem, or
  //  - if full, then replace smallest entry which is smaller than |size|
  for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
    if (shared_mem_cache_[i] == NULL)
      return i;
  }

  size_t smallest_size = size;
  int smallest_index = -1;

  for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) {
    const size_t entry_size = shared_mem_cache_[i]->size();
    if (entry_size < smallest_size) {
      smallest_size = entry_size;
      smallest_index = i;
    }
  }

  if (smallest_index != -1) {
    FreeTransportDIB(shared_mem_cache_[smallest_index]);
    shared_mem_cache_[smallest_index] = NULL;
  }

  return smallest_index;
}

bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) {
  const int slot = FindFreeCacheSlot(mem->size());
  if (slot == -1)
    return false;

  shared_mem_cache_[slot] = mem;
  return true;
}

void RenderProcess::ClearTransportDIBCache() {
  for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) {
    if (shared_mem_cache_[i]) {
      FreeTransportDIB(shared_mem_cache_[i]);
      shared_mem_cache_[i] = NULL;
    }
  }
}
<commit_msg>Remove unused file render_process.cc. render_process_impl.cc is where the action is these days.<commit_after><|endoftext|>


<commit_before>#include "drape_frontend/stylist.hpp"

#include "indexer/feature.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/drawing_rules.hpp"
#include "indexer/drules_include.hpp"
#include "indexer/scales.hpp"

#include "std/bind.hpp"
#include "std/limits.hpp"

namespace df
{

namespace
{

enum Type
{
  Line      =               1,
  Area      = Line       << 1,
  Symbol    = Area       << 1,
  Caption   = Symbol     << 1,
  Circle    = Caption    << 1,
  PathText  = Circle     << 1,
  Waymarker = PathText   << 1,
  Shield    = Waymarker  << 1,
  CountOfType = PathText + 1
};

inline drule::rule_type_t Convert(Type t)
{
  switch (t)
  {
  case Line     : return drule::line;
  case Area     : return drule::area;
  case Symbol   : return drule::symbol;
  case Caption  : return drule::caption;
  case Circle   : return drule::circle;
  case PathText : return drule::pathtext;
  case Waymarker: return drule::waymarker;
  case Shield   : return drule::shield;
  default:
    return drule::count_of_rules;
  }
}

double constexpr kMinPriority = numeric_limits<double>::lowest();

// ==================================== //

inline bool IsTypeOf(drule::Key const & key, int flags)
{
  int currentFlag = Line;
  while (currentFlag < CountOfType)
  {
    Type type = Type(flags & currentFlag);
    if (type != 0 && key.m_type == Convert(type))
      return true;

    currentFlag <<= 1;
  }

  return false;
}

bool IsMiddleTunnel(int const layer, double const depth)
{
  return layer != feature::LAYER_EMPTY && depth < 19000;
}

void FilterRulesByRuntimeSelector(FeatureType const & f, int zoomLevel, drule::KeysT & keys)
{
  keys.erase_if([&f, zoomLevel](drule::Key const & key)->bool
  {
    drule::BaseRule const * const rule = drule::rules().Find(key);
    ASSERT(rule != nullptr, ());
    return !rule->TestFeature(f, zoomLevel);
  });
}

class KeyFunctor
{
public:
  KeyFunctor(FeatureType const & f,
             feature::EGeomType type,
             int const zoomLevel,
             int const keyCount,
             bool isNameExists)
    : m_pointStyleFound(false)
    , m_lineStyleFound(false)
    , m_iconFound(false)
    , m_captionWithoutOffsetFound(false)
    , m_auxCaptionFound(false)
    , m_mainTextType(drule::text_type_name)
    , m_f(f)
    , m_geomType(type)
    , m_zoomLevel(zoomLevel)
    , m_isNameExists(isNameExists)
  {
    m_rules.reserve(keyCount);
    Init();
  }

  void ProcessKey(drule::Key const & key)
  {
    double depth = key.m_priority;
    if (IsMiddleTunnel(m_depthLayer, depth) &&
        IsTypeOf(key, Line | Area | Waymarker))
    {
      double const layerPart = m_depthLayer * drule::layer_base_priority;
      double const depthPart = fmod(depth, drule::layer_base_priority);
      depth = layerPart + depthPart;
    }

    if (IsTypeOf(key, Caption | Symbol | Circle | PathText))
    {
      depth += m_priorityModifier;
      if (m_geomType == feature::GEOM_POINT) ++depth;
    }
    else if (IsTypeOf(key, Area))
      depth -= m_priorityModifier;

    drule::BaseRule const * dRule = drule::rules().Find(key);
    m_rules.push_back(make_pair(dRule, depth));

    bool isNonEmptyCaption = IsTypeOf(key, Caption) && m_isNameExists;
    m_pointStyleFound |= (IsTypeOf(key, Symbol | Circle) || isNonEmptyCaption);
    m_lineStyleFound  |= IsTypeOf(key, Line);
    m_auxCaptionFound |= (dRule->GetCaption(1) != nullptr);

    if (dRule->GetCaption(0) != nullptr)
      m_mainTextType = dRule->GetCaptionTextType(0);
  }

  bool m_pointStyleFound;
  bool m_lineStyleFound;
  bool m_iconFound;
  bool m_captionWithoutOffsetFound;
  bool m_auxCaptionFound;
  buffer_vector<Stylist::TRuleWrapper, 8> m_rules;
  drule::text_type_t m_mainTextType;

private:
  void Init()
  {
    m_depthLayer = m_f.GetLayer();
    if (m_depthLayer == feature::LAYER_TRANSPARENT_TUNNEL)
      m_depthLayer = feature::LAYER_EMPTY;

    if (m_geomType == feature::GEOM_POINT)
      m_priorityModifier = (double)m_f.GetPopulation() / 7E9;
    else
    {
      m2::RectD const r = m_f.GetLimitRect(m_zoomLevel);
      m_priorityModifier = min(1.0, r.SizeX() * r.SizeY() * 10000.0);
    }
  }

private:
  FeatureType const & m_f;
  feature::EGeomType m_geomType;
  int const m_zoomLevel;
  bool const m_isNameExists;
  double m_priorityModifier;
  int m_depthLayer;
};

const uint8_t CoastlineFlag  = 1;
const uint8_t AreaStyleFlag  = 1 << 1;
const uint8_t LineStyleFlag  = 1 << 2;
const uint8_t PointStyleFlag = 1 << 3;

} // namespace

// ==================================== //

void CaptionDescription::Init(FeatureType const & f,
                              int const zoomLevel)
{
  f.GetPreferredNames(m_mainText, m_auxText);

  m_roadNumber = f.GetRoadNumber();
  m_houseNumber = f.GetHouseNumber();

  if (ftypes::IsBuildingChecker::Instance()(f))
  {
    // Mark houses without names/numbers so user can select them by single tap.
    if (m_houseNumber.empty() && m_mainText.empty())
      m_houseNumber = "·";
  }

  SwapCaptions(zoomLevel);
  DiscardLongCaption(zoomLevel);
}

void CaptionDescription::FormatCaptions(FeatureType const & f,
                                        feature::EGeomType type,
                                        drule::text_type_t mainTextType,
                                        bool auxCaptionExists)
{
  if (!auxCaptionExists && !m_auxText.empty() && type != feature::GEOM_LINE)
  {
    f.GetReadableName(m_mainText);
    if (m_mainText == m_auxText)
      m_auxText.clear();
  }

  if (mainTextType == drule::text_type_housenumber)
  {
    m_mainText = move(m_houseNumber);
  }
  else if (mainTextType == drule::text_type_name)
  {
    if (!m_houseNumber.empty())
    {
      if (m_mainText.empty() || m_houseNumber.find(m_mainText) != string::npos)
        m_houseNumber.swap(m_mainText);
      else
        m_mainText += (" (" + m_houseNumber + ")");
    }
  }
}

string const & CaptionDescription::GetMainText() const
{
  return m_mainText;
}

string const & CaptionDescription::GetAuxText() const
{
  return m_auxText;
}

string const & CaptionDescription::GetRoadNumber() const
{
  return m_roadNumber;
}

string CaptionDescription::GetPathName() const
{
  // Always concat names for linear features because we process only one draw rule now.
  if (m_mainText.empty())
    return m_mainText;
  else
    return m_mainText + "   " + m_auxText;
}

bool CaptionDescription::IsNameExists() const
{
  return !m_mainText.empty() || !m_houseNumber.empty();
}

void CaptionDescription::SwapCaptions(int const zoomLevel)
{
  if (zoomLevel <= scales::GetUpperWorldScale() && !m_auxText.empty())
  {
    m_mainText.swap(m_auxText);
    m_auxText.clear();
  }
}

void CaptionDescription::DiscardLongCaption(int const zoomLevel)
{
  if (zoomLevel < 5 && m_mainText.size() > 50)
    m_mainText.clear();
}

// ==================================== //

Stylist::Stylist()
  : m_state(0)
{
}

bool Stylist::IsCoastLine() const
{
  return (m_state & CoastlineFlag) != 0;
}

bool Stylist::AreaStyleExists() const
{
  return (m_state & AreaStyleFlag) != 0;
}

bool Stylist::LineStyleExists() const
{
  return (m_state & LineStyleFlag) != 0;
}

bool Stylist::PointStyleExists() const
{
  return (m_state & PointStyleFlag) != 0;
}

CaptionDescription const & Stylist::GetCaptionDescription() const
{
  return m_captionDescriptor;
}

void Stylist::ForEachRule(Stylist::TRuleCallback const & fn) const
{
  typedef rules_t::const_iterator const_iter;
  for (const_iter it = m_rules.begin(); it != m_rules.end(); ++it)
    fn(*it);
}

bool Stylist::IsEmpty() const
{
  return m_rules.empty();
}

void Stylist::RaiseCoastlineFlag()
{
  m_state |= CoastlineFlag;
}

void Stylist::RaiseAreaStyleFlag()
{
  m_state |= AreaStyleFlag;
}

void Stylist::RaiseLineStyleFlag()
{
  m_state |= LineStyleFlag;
}

void Stylist::RaisePointStyleFlag()
{
  m_state |= PointStyleFlag;
}

CaptionDescription & Stylist::GetCaptionDescriptionImpl()
{
  return m_captionDescriptor;
}

bool InitStylist(FeatureType const & f, int const zoomLevel, bool buildings3d, Stylist & s)
{
  feature::TypesHolder const types(f);

  if (!buildings3d && ftypes::IsBuildingPartChecker::Instance()(types) &&
      !ftypes::IsBuildingChecker::Instance()(types))
    return false;

  drule::KeysT keys;
  pair<int, bool> geomType = feature::GetDrawRule(types, zoomLevel, keys);

  FilterRulesByRuntimeSelector(f, zoomLevel, keys);

  if (keys.empty())
    return false;

  drule::MakeUnique(keys);
  if (geomType.second)
    s.RaiseCoastlineFlag();

  feature::EGeomType mainGeomType = feature::EGeomType(geomType.first);

  switch (mainGeomType)
  {
  case feature::GEOM_POINT:
    s.RaisePointStyleFlag();
    break;
  case feature::GEOM_LINE :
    s.RaiseLineStyleFlag();
    break;
  case feature::GEOM_AREA :
    s.RaiseAreaStyleFlag();
    break;
  default:
    ASSERT(false, ());
    return false;
  }

  CaptionDescription & descr = s.GetCaptionDescriptionImpl();
  descr.Init(f, zoomLevel);

  KeyFunctor keyFunctor(f, mainGeomType, zoomLevel, keys.size(), descr.IsNameExists());
  for_each(keys.begin(), keys.end(), bind(&KeyFunctor::ProcessKey, &keyFunctor, _1));

  if (keyFunctor.m_pointStyleFound)
    s.RaisePointStyleFlag();
  if (keyFunctor.m_lineStyleFound)
    s.RaiseLineStyleFlag();

  s.m_rules.swap(keyFunctor.m_rules);
  descr.FormatCaptions(f, mainGeomType, keyFunctor.m_mainTextType, keyFunctor.m_auxCaptionFound);
  return true;
}

double GetFeaturePriority(FeatureType const & f, int const zoomLevel)
{
  drule::KeysT keys;
  pair<int, bool> const geomType = feature::GetDrawRule(f, zoomLevel, keys);

  FilterRulesByRuntimeSelector(f, zoomLevel, keys);

  feature::EGeomType const mainGeomType = feature::EGeomType(geomType.first);

  KeyFunctor keyFunctor(f, mainGeomType, zoomLevel, keys.size(), false /* isNameExists */);
  for_each(keys.begin(), keys.end(), bind(&KeyFunctor::ProcessKey, &keyFunctor, _1));

  double maxPriority = kMinPriority;
  for (auto const & rule : keyFunctor.m_rules)
  {
    if (rule.second > maxPriority)
      maxPriority = rule.second;
  }

  return maxPriority;
}

} // namespace df
<commit_msg>Postponed IsBuildingChecker<commit_after>#include "drape_frontend/stylist.hpp"

#include "indexer/feature.hpp"
#include "indexer/feature_visibility.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "indexer/drawing_rules.hpp"
#include "indexer/drules_include.hpp"
#include "indexer/scales.hpp"

#include "std/bind.hpp"
#include "std/limits.hpp"

namespace df
{

namespace
{

enum Type
{
  Line      =               1,
  Area      = Line       << 1,
  Symbol    = Area       << 1,
  Caption   = Symbol     << 1,
  Circle    = Caption    << 1,
  PathText  = Circle     << 1,
  Waymarker = PathText   << 1,
  Shield    = Waymarker  << 1,
  CountOfType = PathText + 1
};

inline drule::rule_type_t Convert(Type t)
{
  switch (t)
  {
  case Line     : return drule::line;
  case Area     : return drule::area;
  case Symbol   : return drule::symbol;
  case Caption  : return drule::caption;
  case Circle   : return drule::circle;
  case PathText : return drule::pathtext;
  case Waymarker: return drule::waymarker;
  case Shield   : return drule::shield;
  default:
    return drule::count_of_rules;
  }
}

double constexpr kMinPriority = numeric_limits<double>::lowest();

// ==================================== //

inline bool IsTypeOf(drule::Key const & key, int flags)
{
  int currentFlag = Line;
  while (currentFlag < CountOfType)
  {
    Type type = Type(flags & currentFlag);
    if (type != 0 && key.m_type == Convert(type))
      return true;

    currentFlag <<= 1;
  }

  return false;
}

bool IsMiddleTunnel(int const layer, double const depth)
{
  return layer != feature::LAYER_EMPTY && depth < 19000;
}

void FilterRulesByRuntimeSelector(FeatureType const & f, int zoomLevel, drule::KeysT & keys)
{
  keys.erase_if([&f, zoomLevel](drule::Key const & key)->bool
  {
    drule::BaseRule const * const rule = drule::rules().Find(key);
    ASSERT(rule != nullptr, ());
    return !rule->TestFeature(f, zoomLevel);
  });
}

class KeyFunctor
{
public:
  KeyFunctor(FeatureType const & f,
             feature::EGeomType type,
             int const zoomLevel,
             int const keyCount,
             bool isNameExists)
    : m_pointStyleFound(false)
    , m_lineStyleFound(false)
    , m_iconFound(false)
    , m_captionWithoutOffsetFound(false)
    , m_auxCaptionFound(false)
    , m_mainTextType(drule::text_type_name)
    , m_f(f)
    , m_geomType(type)
    , m_zoomLevel(zoomLevel)
    , m_isNameExists(isNameExists)
  {
    m_rules.reserve(keyCount);
    Init();
  }

  void ProcessKey(drule::Key const & key)
  {
    double depth = key.m_priority;
    if (IsMiddleTunnel(m_depthLayer, depth) &&
        IsTypeOf(key, Line | Area | Waymarker))
    {
      double const layerPart = m_depthLayer * drule::layer_base_priority;
      double const depthPart = fmod(depth, drule::layer_base_priority);
      depth = layerPart + depthPart;
    }

    if (IsTypeOf(key, Caption | Symbol | Circle | PathText))
    {
      depth += m_priorityModifier;
      if (m_geomType == feature::GEOM_POINT) ++depth;
    }
    else if (IsTypeOf(key, Area))
      depth -= m_priorityModifier;

    drule::BaseRule const * dRule = drule::rules().Find(key);
    m_rules.push_back(make_pair(dRule, depth));

    bool isNonEmptyCaption = IsTypeOf(key, Caption) && m_isNameExists;
    m_pointStyleFound |= (IsTypeOf(key, Symbol | Circle) || isNonEmptyCaption);
    m_lineStyleFound  |= IsTypeOf(key, Line);
    m_auxCaptionFound |= (dRule->GetCaption(1) != nullptr);

    if (dRule->GetCaption(0) != nullptr)
      m_mainTextType = dRule->GetCaptionTextType(0);
  }

  bool m_pointStyleFound;
  bool m_lineStyleFound;
  bool m_iconFound;
  bool m_captionWithoutOffsetFound;
  bool m_auxCaptionFound;
  buffer_vector<Stylist::TRuleWrapper, 8> m_rules;
  drule::text_type_t m_mainTextType;

private:
  void Init()
  {
    m_depthLayer = m_f.GetLayer();
    if (m_depthLayer == feature::LAYER_TRANSPARENT_TUNNEL)
      m_depthLayer = feature::LAYER_EMPTY;

    if (m_geomType == feature::GEOM_POINT)
      m_priorityModifier = (double)m_f.GetPopulation() / 7E9;
    else
    {
      m2::RectD const r = m_f.GetLimitRect(m_zoomLevel);
      m_priorityModifier = min(1.0, r.SizeX() * r.SizeY() * 10000.0);
    }
  }

private:
  FeatureType const & m_f;
  feature::EGeomType m_geomType;
  int const m_zoomLevel;
  bool const m_isNameExists;
  double m_priorityModifier;
  int m_depthLayer;
};

const uint8_t CoastlineFlag  = 1;
const uint8_t AreaStyleFlag  = 1 << 1;
const uint8_t LineStyleFlag  = 1 << 2;
const uint8_t PointStyleFlag = 1 << 3;

} // namespace

// ==================================== //

void CaptionDescription::Init(FeatureType const & f,
                              int const zoomLevel)
{
  f.GetPreferredNames(m_mainText, m_auxText);

  m_roadNumber = f.GetRoadNumber();
  m_houseNumber = f.GetHouseNumber();

  // Mark houses without names/numbers so user can select them by single tap.
  if (m_houseNumber.empty() && m_mainText.empty() && ftypes::IsBuildingChecker::Instance()(f))
    m_houseNumber = "·";

  SwapCaptions(zoomLevel);
  DiscardLongCaption(zoomLevel);
}

void CaptionDescription::FormatCaptions(FeatureType const & f,
                                        feature::EGeomType type,
                                        drule::text_type_t mainTextType,
                                        bool auxCaptionExists)
{
  if (!auxCaptionExists && !m_auxText.empty() && type != feature::GEOM_LINE)
  {
    f.GetReadableName(m_mainText);
    if (m_mainText == m_auxText)
      m_auxText.clear();
  }

  if (mainTextType == drule::text_type_housenumber)
  {
    m_mainText = move(m_houseNumber);
  }
  else if (mainTextType == drule::text_type_name)
  {
    if (!m_houseNumber.empty())
    {
      if (m_mainText.empty() || m_houseNumber.find(m_mainText) != string::npos)
        m_houseNumber.swap(m_mainText);
      else
        m_mainText += (" (" + m_houseNumber + ")");
    }
  }
}

string const & CaptionDescription::GetMainText() const
{
  return m_mainText;
}

string const & CaptionDescription::GetAuxText() const
{
  return m_auxText;
}

string const & CaptionDescription::GetRoadNumber() const
{
  return m_roadNumber;
}

string CaptionDescription::GetPathName() const
{
  // Always concat names for linear features because we process only one draw rule now.
  if (m_mainText.empty())
    return m_mainText;
  else
    return m_mainText + "   " + m_auxText;
}

bool CaptionDescription::IsNameExists() const
{
  return !m_mainText.empty() || !m_houseNumber.empty();
}

void CaptionDescription::SwapCaptions(int const zoomLevel)
{
  if (zoomLevel <= scales::GetUpperWorldScale() && !m_auxText.empty())
  {
    m_mainText.swap(m_auxText);
    m_auxText.clear();
  }
}

void CaptionDescription::DiscardLongCaption(int const zoomLevel)
{
  if (zoomLevel < 5 && m_mainText.size() > 50)
    m_mainText.clear();
}

// ==================================== //

Stylist::Stylist()
  : m_state(0)
{
}

bool Stylist::IsCoastLine() const
{
  return (m_state & CoastlineFlag) != 0;
}

bool Stylist::AreaStyleExists() const
{
  return (m_state & AreaStyleFlag) != 0;
}

bool Stylist::LineStyleExists() const
{
  return (m_state & LineStyleFlag) != 0;
}

bool Stylist::PointStyleExists() const
{
  return (m_state & PointStyleFlag) != 0;
}

CaptionDescription const & Stylist::GetCaptionDescription() const
{
  return m_captionDescriptor;
}

void Stylist::ForEachRule(Stylist::TRuleCallback const & fn) const
{
  typedef rules_t::const_iterator const_iter;
  for (const_iter it = m_rules.begin(); it != m_rules.end(); ++it)
    fn(*it);
}

bool Stylist::IsEmpty() const
{
  return m_rules.empty();
}

void Stylist::RaiseCoastlineFlag()
{
  m_state |= CoastlineFlag;
}

void Stylist::RaiseAreaStyleFlag()
{
  m_state |= AreaStyleFlag;
}

void Stylist::RaiseLineStyleFlag()
{
  m_state |= LineStyleFlag;
}

void Stylist::RaisePointStyleFlag()
{
  m_state |= PointStyleFlag;
}

CaptionDescription & Stylist::GetCaptionDescriptionImpl()
{
  return m_captionDescriptor;
}

bool InitStylist(FeatureType const & f, int const zoomLevel, bool buildings3d, Stylist & s)
{
  feature::TypesHolder const types(f);

  if (!buildings3d && ftypes::IsBuildingPartChecker::Instance()(types) &&
      !ftypes::IsBuildingChecker::Instance()(types))
    return false;

  drule::KeysT keys;
  pair<int, bool> geomType = feature::GetDrawRule(types, zoomLevel, keys);

  FilterRulesByRuntimeSelector(f, zoomLevel, keys);

  if (keys.empty())
    return false;

  drule::MakeUnique(keys);
  if (geomType.second)
    s.RaiseCoastlineFlag();

  feature::EGeomType mainGeomType = feature::EGeomType(geomType.first);

  switch (mainGeomType)
  {
  case feature::GEOM_POINT:
    s.RaisePointStyleFlag();
    break;
  case feature::GEOM_LINE :
    s.RaiseLineStyleFlag();
    break;
  case feature::GEOM_AREA :
    s.RaiseAreaStyleFlag();
    break;
  default:
    ASSERT(false, ());
    return false;
  }

  CaptionDescription & descr = s.GetCaptionDescriptionImpl();
  descr.Init(f, zoomLevel);

  KeyFunctor keyFunctor(f, mainGeomType, zoomLevel, keys.size(), descr.IsNameExists());
  for_each(keys.begin(), keys.end(), bind(&KeyFunctor::ProcessKey, &keyFunctor, _1));

  if (keyFunctor.m_pointStyleFound)
    s.RaisePointStyleFlag();
  if (keyFunctor.m_lineStyleFound)
    s.RaiseLineStyleFlag();

  s.m_rules.swap(keyFunctor.m_rules);
  descr.FormatCaptions(f, mainGeomType, keyFunctor.m_mainTextType, keyFunctor.m_auxCaptionFound);
  return true;
}

double GetFeaturePriority(FeatureType const & f, int const zoomLevel)
{
  drule::KeysT keys;
  pair<int, bool> const geomType = feature::GetDrawRule(f, zoomLevel, keys);

  FilterRulesByRuntimeSelector(f, zoomLevel, keys);

  feature::EGeomType const mainGeomType = feature::EGeomType(geomType.first);

  KeyFunctor keyFunctor(f, mainGeomType, zoomLevel, keys.size(), false /* isNameExists */);
  for_each(keys.begin(), keys.end(), bind(&KeyFunctor::ProcessKey, &keyFunctor, _1));

  double maxPriority = kMinPriority;
  for (auto const & rule : keyFunctor.m_rules)
  {
    if (rule.second > maxPriority)
      maxPriority = rule.second;
  }

  return maxPriority;
}

} // namespace df
<|endoftext|>


<commit_before>#pragma once

#include <string>

namespace graph {
		struct WeightedProperty {
			int weight;

		    bool operator==(WeightedProperty const& other) const {
			    return weight == other.weight;
		    }
		};

		template <typename State>
		struct AstarNodeProperty {
			int gScore;
			int hScore;

			std::string parent;

			State state;

		    bool operator==(AstarNodeProperty const& other) const {
			    return (gScore == other.gScore) && (hScore == other.hScore) &&
			           (parent == other.parent) && (state == other.state);
		    }
		};

		template <>
		struct AstarNodeProperty<void> {
			int gScore;
			int hScore;

			std::string parent;

		    bool operator==(AstarNodeProperty const& other) const {
			    return (gScore == other.gScore) && (hScore == other.hScore) &&
			           (parent == other.parent);
		    }
		};

	    struct NoProperty {
		    bool operator==(NoProperty const&) const {
			    return true;
		    }
	    };
}
<commit_msg>Removing useless parent in AstarNodeProperty<commit_after>#pragma once

#include <string>

namespace graph {
		struct WeightedProperty {
			int weight;

		    bool operator==(WeightedProperty const& other) const {
			    return weight == other.weight;
		    }
		};

		template <typename State>
		struct AstarNodeProperty {
			int gScore;
			int hScore;

			State state;

		    bool operator==(AstarNodeProperty const& other) const {
			    return (gScore == other.gScore) && (hScore == other.hScore) &&
			           (state == other.state);
		    }
		};

		template <>
		struct AstarNodeProperty<void> {
			int gScore;
			int hScore;

		    bool operator==(AstarNodeProperty const& other) const {
			    return (gScore == other.gScore) && (hScore == other.hScore);
		    }
		};

	    struct NoProperty {
		    bool operator==(NoProperty const&) const {
			    return true;
		    }
	    };
}
<|endoftext|>