view dw/types.cc @ 2030:382160be8c2f

cookies comments I was going to say something in the comments about simplicity and not implementing every little bit of the rfc when we don't know of cookies that make it necessary, but then I suppose that's all implied with dillo.
author corvid <corvid@lavabit.com>
date Tue, 17 May 2011 22:48:50 +0000
parents 6811278a670c
children
line wrap: on
line source
/*
 * Dillo Widget
 *
 * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */



#include "core.hh"
#include "../lout/msg.h"

using namespace lout;

namespace dw {
namespace core {

Rectangle::Rectangle (int x, int y, int width, int height)
{
   this->x = x;
   this->y = y;
   this->width = width;
   this->height = height;
}

/*
 * Draw rectangle in view relative to point (x,y).
 */
void Rectangle::draw (core::View *view, core::style::Style *style, int x,int y)
{
   const bool filled = false;

   view->drawRectangle(style->color, core::style::Color::SHADING_NORMAL,filled,
                       x + this->x, y + this->y, this->width, this->height);
}

/**
 * Return whether this rectangle and otherRect intersect. If yes,
 * return the intersection rectangle in dest.
 */
bool Rectangle::intersectsWith (Rectangle *otherRect, Rectangle *dest)
{
   bool doIntersect =
      this->x < otherRect->x + otherRect->width &&
      this->y < otherRect->y + otherRect->height &&
      otherRect->x < this->x + this->width &&
      otherRect->y < this->y + this->height;

   if (doIntersect) {
      dest->x = misc::max(this->x, otherRect->x);
      dest->y = misc::max(this->y, otherRect->y);
      dest->width  = misc::min(this->x + this->width,
                               otherRect->x + otherRect->width) - dest->x;
      dest->height = misc::min(this->y + this->height,
                               otherRect->y + otherRect->height) - dest->y;
   } else {
      dest->x = dest->y = dest->width = dest->height = 0;
   }

   return doIntersect;
}

/*
 * Return whether this is a subset of otherRect.
 */
bool Rectangle::isSubsetOf (Rectangle *otherRect)
{
   return
      x >= otherRect->x &&
      y >= otherRect->y &&
      x + width <= otherRect->x + otherRect->width &&
      y + height <= otherRect->y + otherRect->height;
}

bool Rectangle::isPointWithin (int x, int y)
{
   return
      x >= this->x && y >= this->y &&
      x < this->x + width && y < this->y + height;
}

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

Circle::Circle (int x, int y, int radius)
{
   this->x = x;
   this->y = y;
   this->radius = radius;
}

/*
 * Draw circle in view relative to point (x,y).
 */
void Circle::draw (core::View *view, core::style::Style *style, int x, int y)
{
   const bool filled = false;

   view->drawArc(style->color, core::style::Color::SHADING_NORMAL, filled,
                 x + this->x, y + this->y, 2 * this->radius, 2 * this->radius,
                 0, 360);
}

bool Circle::isPointWithin (int x, int y)
{
   return
      (x - this->x) * (x - this->x) + (y - this->y) * (y - this->y)
      <= radius * radius;
}

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

Polygon::Polygon ()
{
   points = new misc::SimpleVector<Point> (8);
   minx = miny = 0xffffff;
   maxx = maxy = -0xffffff;
}

Polygon::~Polygon ()
{
   delete points;
}

/*
 * Draw polygon in view relative to point (x,y).
 */
void Polygon::draw (core::View *view, core::style::Style *style, int x, int y)
{
   if (points->size()) {
      int i;
      const bool filled = false, convex = false;
      int (*pointArray)[2] =
                     (int (*)[2]) malloc(points->size() * sizeof(*pointArray));

      for (i = 0; i < points->size(); i++) {
         pointArray[i][0] = x + points->getRef(i)->x;
         pointArray[i][1] = y + points->getRef(i)->y;
      }
      view->drawPolygon(style->color, core::style::Color::SHADING_NORMAL,
                        filled, convex, pointArray, i);
      free(pointArray);
   }
}

void Polygon::addPoint (int x, int y)
{
   points->increase ();
   points->getRef(points->size () - 1)->x = x;
   points->getRef(points->size () - 1)->y = y;

   minx = misc::min(minx, x);
   miny = misc::min(miny, y);
   maxx = misc::max(maxx, x);
   maxy = misc::max(maxy, y);
}

/**
 * \brief Return, whether the line, limited by (ax1, ay1) and (ax2, ay2),
 *    crosses the unlimited line, determined by two points (bx1, by1) and
 *    (bx2, by2).
 */
bool Polygon::linesCross0(int ax1, int ay1, int ax2, int ay2,
                          int bx1, int by1, int bx2, int by2)
{
   /** TODO Some more description */
   // If the scalar product is 0, it means that one point is on the second
   // line, so we check for <= 0, not < 0.
   int z1 = zOfVectorProduct (ax1 - bx1, ay1 - by1, bx2 - bx1, by2 - by1);
   int z2 = zOfVectorProduct (ax2 - bx1, ay2 - by1, bx2 - bx1, by2 - by1);

   return (z1 <= 0 && z2 >= 0) || (z1 >= 0 && z2 <= 0);
}

/**
 * \brief Return, whether the line, limited by (ax1, ay1) and (ax2, ay2),
 *    crosses the line, limited by (bx1, by1) and (bx2, by2).
 */
bool Polygon::linesCross(int ax1, int ay1, int ax2, int ay2,
                         int bx1, int by1, int bx2, int by2)
{
   bool cross =
      linesCross0 (ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) &&
      linesCross0 (bx1, by1, bx2, by2, ax1, ay1, ax2, ay2);
   _MSG("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
        ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
   return cross;
}

bool Polygon::isPointWithin (int x, int y)
{
   if (points->size () < 3 ||
       (x < minx || x > maxx || y < miny || y >= maxy))
      return false;
   else {
      int numCrosses = 0;
      for (int i = 0; i < points->size () - 1; i++) {
         if (linesCross (minx - 1, miny - 1, x, y,
                         points->getRef(i)->x, points->getRef(i)->y,
                         points->getRef(i + 1)->x, points->getRef(i + 1)->y))
            numCrosses++;
      }
      if (linesCross (minx - 1, miny - 1, x, y,
                      points->getRef(points->size () - 1)->x,
                      points->getRef(points->size () - 1)->y,
                      points->getRef(0)->x, points->getRef(0)->y))
         numCrosses++;

      return numCrosses % 2 == 1;
   }
}

Region::Region()
{
   rectangleList = new container::typed::List <Rectangle> (true);
}

Region::~Region()
{
   delete rectangleList;
}

/**
 * \brief Add a rectangle to the region and combine it with
 * existing rectangles if possible.
 * The number of rectangles is forced to be less than 16
 * by combining excessive rectangles.
 */
void Region::addRectangle (Rectangle *rPointer)
{
   container::typed::Iterator <Rectangle> it;
   Rectangle *r = new Rectangle (rPointer->x, rPointer->y,
      rPointer->width, rPointer->height);

   for (it = rectangleList->iterator (); it.hasNext (); ) {
      Rectangle *ownRect = it.getNext ();

      int combinedHeight =
         misc::max(r->y + r->height, ownRect->y + ownRect->height) -
         misc::min(r->y, ownRect->y);
      int combinedWidth =
         misc::max(r->x + r->width, ownRect->x + ownRect->width) -
         misc::min(r->x, ownRect->x);

      if (rectangleList->size() >= 16 ||
         combinedWidth * combinedHeight <=
         ownRect->width * ownRect->height + r->width * r->height) {

            r->x = misc::min(r->x, ownRect->x);
            r->y = misc::min(r->y, ownRect->y);
            r->width = combinedWidth;
            r->height = combinedHeight;

            rectangleList->removeRef (ownRect);
      }
   }

   rectangleList->append (r);
}

} // namespace dw
} // namespace core