dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

image.cc
Go to the documentation of this file.
1 /*
2  * Dillo Widget
3  *
4  * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 
22 #include "image.hh"
23 #include "../lout/msg.h"
24 #include "../lout/misc.hh"
25 #include "../lout/debug.hh"
26 
27 namespace dw {
28 
29 using namespace lout;
30 
32 {
33  shapesAndLinks = new container::typed::List <ShapeAndLink> (true);
34  defaultLink = -1;
35 }
36 
38 {
39  delete shapesAndLinks;
40 }
41 
43  int x, int y)
44 {
46 
47  for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
48  ShapeAndLink *shapeAndLink = it.getNext ();
49 
50  shapeAndLink->shape->draw(view, style, x, y);
51  }
52 }
53 
54 void ImageMapsList::ImageMap::add (core::Shape *shape, int link) {
55  ShapeAndLink *shapeAndLink = new ShapeAndLink ();
56  shapeAndLink->shape = shape;
57  shapeAndLink->link = link;
58  shapesAndLinks->append (shapeAndLink);
59 }
60 
61 int ImageMapsList::ImageMap::link (int x, int y) {
63  int link = defaultLink;
64 
65  for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
66  ShapeAndLink *shapeAndLink = it.getNext ();
67 
68  if (shapeAndLink->shape->isPointWithin (x, y)) {
69  link = shapeAndLink->link;
70  break;
71  }
72  }
73 
74  return link;
75 }
76 
78 {
80  (true, true);
81  currentMap = NULL;
82 }
83 
85 {
86  delete imageMaps;
87 }
88 
97 {
98  currentMap = new ImageMap ();
99  imageMaps->put (key, currentMap);
100 }
101 
109 {
110  currentMap->add (shape, link);
111 }
112 
117 {
118  currentMap->setDefaultLink (link);
119 }
120 
122  core::style::Style *style, int x, int y)
123 {
124  ImageMap *map = imageMaps->get (key);
125 
126  if (map)
127  map->draw(view, style, x, y);
128 }
129 
131 {
132  int link = -1;
133  ImageMap *map = imageMaps->get (key);
134 
135  if (map)
136  link = map->link (x, y);
137 
138  return link;
139 }
140 
141 // ----------------------------------------------------------------------
142 
143 int Image::CLASS_ID = -1;
144 
145 Image::Image(const char *altText)
146 {
147  DBG_OBJ_CREATE ("dw::Image");
148  registerName ("dw::Image", &CLASS_ID);
149  this->altText = altText ? strdup (altText) : NULL;
150  altTextWidth = -1; // not yet calculated
151  buffer = NULL;
152  clicking = false;
153  currLink = -1;
154  mapList = NULL;
155  mapKey = NULL;
156  isMap = false;
157 }
158 
160 {
161  if (altText)
162  free(altText);
163  if (buffer)
164  buffer->unref ();
165  if (mapKey)
166  delete mapKey;
167 
168  DBG_OBJ_DELETE ();
169 }
170 
172 {
173  if (buffer) {
174  if (getStyle ()->height == core::style::LENGTH_AUTO &&
175  core::style::isAbsLength (getStyle ()->width) &&
176  buffer->getRootWidth () > 0) {
177  // preserve aspect ratio when only width is given
178  requisition->width = core::style::absLengthVal (getStyle ()->width);
179  requisition->ascent = buffer->getRootHeight () *
180  requisition->width / buffer->getRootWidth ();
181  } else if (getStyle ()->width == core::style::LENGTH_AUTO &&
182  core::style::isAbsLength (getStyle ()->height) &&
183  buffer->getRootHeight () > 0) {
184  // preserve aspect ratio when only height is given
185  requisition->ascent = core::style::absLengthVal (getStyle ()->height);
186  requisition->width = buffer->getRootWidth () *
187  requisition->ascent / buffer->getRootHeight ();
188  } else {
189  requisition->width = buffer->getRootWidth ();
190  requisition->ascent = buffer->getRootHeight ();
191  }
192  requisition->descent = 0;
193  } else {
194  if (altText && altText[0]) {
195  if (altTextWidth == -1)
196  altTextWidth =
197  layout->textWidth (getStyle()->font, altText, strlen (altText));
198 
199  requisition->width = altTextWidth;
200  requisition->ascent = getStyle()->font->ascent;
201  requisition->descent = getStyle()->font->descent;
202  } else {
203  requisition->width = 0;
204  requisition->ascent = 0;
205  requisition->descent = 0;
206  }
207  }
208 
209  requisition->width += getStyle()->boxDiffWidth ();
210  requisition->ascent += getStyle()->boxOffsetY ();
211  requisition->descent += getStyle()->boxRestHeight ();
212 }
213 
215 {
216  core::Imgbuf *oldBuffer;
217  int dx, dy;
218 
219  /* if image is moved only */
220  if (allocation->width == this->allocation.width &&
221  allocation->ascent + allocation->descent == getHeight ())
222  return;
223 
224  dx = getStyle()->boxDiffWidth ();
225  dy = getStyle()->boxDiffHeight ();
226 #if 0
227  MSG("boxDiffHeight = %d + %d, buffer=%p\n",
228  getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
229  MSG("getContentWidth() = allocation.width - style->boxDiffWidth ()"
230  " = %d - %d = %d\n",
231  this->allocation.width, getStyle()->boxDiffWidth(),
232  this->allocation.width - getStyle()->boxDiffWidth());
233  MSG("getContentHeight() = getHeight() - style->boxDiffHeight ()"
234  " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
235  this->getHeight() - getStyle()->boxDiffHeight());
236 #endif
237  if (buffer &&
238  (allocation->width - dx > 0 ||
239  allocation->ascent + allocation->descent - dy > 0)) {
240  // Zero content size : simply wait...
241  // Only one dimension: naturally scale
242  oldBuffer = buffer;
243  buffer = oldBuffer->getScaledBuf (allocation->width - dx,
244  allocation->ascent
245  + allocation->descent - dy);
246  oldBuffer->unref ();
247  }
248 }
249 
251 {
252  // BUG: this is wrong for image maps, but the cursor position is unknown.
253  currLink = getStyle()->x_link;
254 
255  if (currLink != -1) {
256  (void) layout->emitLinkEnter (this, currLink, -1, -1, -1);
257  }
258  Widget::enterNotifyImpl(event);
259 }
260 
262 {
263  clicking = false;
264 
265  if (currLink != -1) {
266  currLink = -1;
267  (void) layout->emitLinkEnter (this, -1, -1, -1, -1);
268  }
269  Widget::leaveNotifyImpl(event);
270 }
271 
272 /*
273  * Return the coordinate relative to the contents.
274  * If the event occurred in the surrounding box, return the value at the
275  * edge of the contents instead.
276  */
278 {
279  int ret = event->xWidget - getStyle()->boxOffsetX();
280 
281  ret = misc::min(getContentWidth(), misc::max(ret, 0));
282  return ret;
283 }
284 
286 {
287  int ret = event->yWidget - getStyle()->boxOffsetY();
288 
289  ret = misc::min(getContentHeight(), misc::max(ret, 0));
290  return ret;
291 }
292 
294 {
295  if (mapList || isMap) {
296  int x = contentX(event);
297  int y = contentY(event);
298 
299  if (mapList) {
300  /* client-side image map */
301  int newLink = mapList->link (mapKey, x, y);
302  if (newLink != currLink) {
303  currLink = newLink;
304  clicking = false;
305  /* \todo Using MAP/AREA styles would probably be best */
306  setCursor(newLink == -1 ? getStyle()->cursor :
308  (void) layout->emitLinkEnter (this, newLink, -1, -1, -1);
309  }
310  } else if (isMap && currLink != -1) {
311  /* server-side image map */
312  (void) layout->emitLinkEnter (this, currLink, -1, x, y);
313  }
314  }
315  return true;
316 }
317 
319 {
320  bool ret = false;
321 
322  currLink = mapList ? mapList->link(mapKey,contentX(event),contentY(event)) :
323  getStyle()->x_link;
324  if (event->button == 3){
325  (void)layout->emitLinkPress(this, currLink, getStyle()->x_img, -1, -1,
326  event);
327  ret = true;
328  } else if (event->button == 1 || currLink != -1){
329  clicking = true;
330  ret = true;
331  }
332  return ret;
333 }
334 
336 {
337  currLink = mapList ? mapList->link(mapKey,contentX(event),contentY(event)) :
338  getStyle()->x_link;
339  if (clicking) {
340  int x = isMap ? contentX(event) : -1;
341  int y = isMap ? contentY(event) : -1;
342  clicking = false;
343  layout->emitLinkClick (this, currLink, getStyle()->x_img, x, y, event);
344  return true;
345  }
346  return false;
347 }
348 
350 {
351  int dx, dy;
352  core::Rectangle content, intersection;
353 
354  drawWidgetBox (view, area, false);
355 
356  if (buffer) {
357  dx = getStyle()->boxOffsetX ();
358  dy = getStyle()->boxOffsetY ();
359  content.x = dx;
360  content.y = dy;
361  content.width = getContentWidth ();
362  content.height = getContentHeight ();
363 
364  if (area->intersectsWith (&content, &intersection))
365  view->drawImage (buffer,
366  allocation.x + dx, allocation.y + dy,
367  intersection.x - dx, intersection.y - dy,
368  intersection.width, intersection.height);
369  } else {
370  core::View *clippingView;
371 
372  if (altText && altText[0]) {
373  core::View *usedView = view;
374 
375  clippingView = NULL;
376 
377  if (altTextWidth == -1)
378  altTextWidth =
379  layout->textWidth (getStyle()->font, altText, strlen (altText));
380 
381  if ((getContentWidth() < altTextWidth) ||
382  (getContentHeight() <
383  getStyle()->font->ascent + getStyle()->font->descent)) {
384  clippingView = usedView =
385  view->getClippingView (allocation.x + getStyle()->boxOffsetX (),
386  allocation.y + getStyle()->boxOffsetY (),
387  getContentWidth(),
388  getContentHeight());
389  }
390 
391  usedView->drawSimpleWrappedText (getStyle()->font, getStyle()->color,
393  allocation.x + getStyle()->boxOffsetX (),
394  allocation.y + getStyle()->boxOffsetY (),
395  getContentWidth(), getContentHeight(), altText);
396 
397  if (clippingView)
398  view->mergeClippingView (clippingView);
399  }
400  if (mapKey) {
401  clippingView = view->getClippingView (allocation.x +
402  getStyle()->boxOffsetX (),
403  allocation.y +
404  getStyle()->boxOffsetY (),
405  getContentWidth(),
406  getContentHeight());
407  mapList->drawMap(mapKey, clippingView, getStyle(),
408  allocation.x + getStyle()->boxOffsetX (),
409  allocation.y + getStyle()->boxOffsetY ());
410  view->mergeClippingView (clippingView);
411  }
412  }
413 
415 }
416 
418 {
419  //return new core::TextIterator (this, mask, atEnd, altText);
421  return new core::EmptyIterator (this, mask, atEnd);
422 }
423 
424 void Image::setBuffer (core::Imgbuf *buffer, bool resize)
425 {
426  core::Imgbuf *oldBuf = this->buffer;
427 
428  if (wasAllocated () && needsResize () &&
429  getContentWidth () > 0 && getContentHeight () > 0) {
430  // Don't create a new buffer for the transition from alt text to img,
431  // and only scale when both dimensions are known.
432  this->buffer =
433  buffer->getScaledBuf (getContentWidth (), getContentHeight ());
434  } else {
435  this->buffer = buffer;
436  buffer->ref ();
437  }
438  queueResize (0, true);
439 
440  DBG_OBJ_ASSOC_CHILD (this->buffer);
441 
442  if (oldBuf)
443  oldBuf->unref ();
444 }
445 
446 void Image::drawRow (int row)
447 {
448  core::Rectangle area;
449 
450  assert (buffer != NULL);
451 
452  buffer->getRowArea (row, &area);
453  if (area.width && area.height)
454  queueDrawArea (area.x + getStyle()->boxOffsetX (),
455  area.y + getStyle()->boxOffsetY (),
456  area.width, area.height);
457 }
458 
460 {
461  // Nothing to do; images are always drawn line by line.
462 }
463 
465 {
466  // Could display an error.
467 }
468 
469 
474 {
475  isMap = true;
476 }
477 
478 
487 {
488  mapList = list;
489  if (mapKey && mapKey != key)
490  delete mapKey;
491  mapKey = key;
492 }
493 
494 } // namespace dw
DBG_OBJ_DELETE
#define DBG_OBJ_DELETE()
Definition: debug.hh:176
dw::Image::enterNotifyImpl
void enterNotifyImpl(core::EventCrossing *event)
Definition: image.cc:250
dw::Image::buttonPressImpl
bool buttonPressImpl(core::EventButton *event)
Definition: image.cc:318
dw::core::View::mergeClippingView
virtual void mergeClippingView(View *clippingView)=0
dw::core::style::absLengthVal
int absLengthVal(Length l)
Returns the value of a length in pixels, as an integer.
Definition: style.hh:412
DBG_OBJ_CREATE
#define DBG_OBJ_CREATE(klass)
Definition: debug.hh:175
MSG
#define MSG(...)
Definition: bookmarks.c:45
dw::core::Requisition
Definition: types.hh:172
dw::ImageMapsList::ImageMap::ImageMap
ImageMap()
Definition: image.cc:31
dw::core::EventButton::button
int button
Definition: events.hh:61
dw::Image::setIsMap
void setIsMap()
Sets image as server side image map.
Definition: image.cc:473
dw::core::MousePositionEvent
Base class for all mouse events related to a specific position.
Definition: events.hh:48
dw::core::EventCrossing
Represents a enter or leave notify event.
Definition: events.hh:74
dw::core::EventButton
Represents a button press or release event.
Definition: events.hh:57
dw::core::style::LENGTH_AUTO
Represents "auto" lengths.
Definition: style.hh:454
dw::core::Requisition::descent
int descent
Definition: types.hh:176
dw::core::style::CURSOR_POINTER
Definition: style.hh:201
dw::ImageMapsList::ImageMap::link
int link(int x, int y)
Definition: image.cc:61
dw::Image::draw
void draw(core::View *view, core::Rectangle *area)
Definition: image.cc:349
dw::Image::drawRow
void drawRow(int row)
Called, when data from a row is available and has been copied into the image buffer.
Definition: image.cc:446
dw::Image::sizeAllocateImpl
void sizeAllocateImpl(core::Allocation *allocation)
See Sizes of Dillo Widgets.
Definition: image.cc:214
dw::core::Content::Type
Type
Definition: types.hh:187
dw::core::View::drawSimpleWrappedText
virtual void drawSimpleWrappedText(style::Font *font, style::Color *color, style::Color::Shading shading, int x, int y, int w, int h, const char *text)=0
dw::Image::setUseMap
void setUseMap(ImageMapsList *list, Object *key)
Sets image as client side image map.
Definition: image.cc:486
dw::core::Iterator
Iterators are used to iterate through the contents of a widget.
Definition: iterator.hh:19
lout::container::typed::Iterator::hasNext
bool hasNext()
Definition: container.hh:369
dw::core::EmptyIterator
This implementation of dw::core::Iterator can be used by widgets with no contents.
Definition: iterator.hh:95
dw::core::Rectangle::intersectsWith
bool intersectsWith(Rectangle *otherRect, Rectangle *dest)
Definition: types.cc:53
dw::Image::~Image
~Image()
Definition: image.cc:159
dw::core::Imgbuf::getScaledBuf
virtual Imgbuf * getScaledBuf(int width, int height)=0
image.hh
dw::core::Rectangle::x
int x
Definition: types.hh:72
key
Definition: colors.c:28
dw::Image::sizeRequestImpl
void sizeRequestImpl(core::Requisition *requisition)
See Sizes of Dillo Widgets.
Definition: image.cc:171
dw::core::Allocation
Represents the allocation, i.e. actual position and size of a dw::core::Widget.
Definition: types.hh:163
dw::Image::buttonReleaseImpl
bool buttonReleaseImpl(core::EventButton *event)
Definition: image.cc:335
dw::ImageMapsList::ImageMap
Definition: image.hh:26
dw::core::View::drawImage
virtual void drawImage(Imgbuf *imgbuf, int xRoot, int yRoot, int x, int y, int width, int height)=0
lout::misc::max
T max(T a, T b)
Definition: misc.hh:20
DBG_OBJ_ASSOC_CHILD
#define DBG_OBJ_ASSOC_CHILD(child)
Definition: debug.hh:179
dw::ImageMapsList::ImageMap::~ImageMap
~ImageMap()
Definition: image.cc:37
lout::misc::min
T min(T a, T b)
Definition: misc.hh:19
lout::container::typed::Iterator
Typed version of container::untyped::Iterator.
Definition: container.hh:352
dw::core::Allocation::descent
int descent
Definition: types.hh:169
dw::core::style::Color::SHADING_NORMAL
Definition: style.hh:725
lout::container::typed::HashTable
Typed version of container::untyped::HashTable.
Definition: container.hh:475
dw::Image::contentX
int contentX(core::MousePositionEvent *event)
Definition: image.cc:277
lout::object::Object
This is the base class for many other classes, which defines very common virtual methods.
Definition: object.hh:24
dw::ImageMapsList::ImageMap::add
void add(core::Shape *shape, int link)
Definition: image.cc:54
dw::core::Rectangle::height
int height
Definition: types.hh:75
dw::core::EventMotion
Represents a mouse motion event.
Definition: events.hh:67
dw::core::Requisition::ascent
int ascent
Definition: types.hh:175
dw::Image::leaveNotifyImpl
void leaveNotifyImpl(core::EventCrossing *event)
Definition: image.cc:261
lout
Definition: container.cc:26
dw::core::Shape::draw
virtual void draw(core::View *view, core::style::Style *style, int x, int y)=0
dw::Image::iterator
core::Iterator * iterator(core::Content::Type mask, bool atEnd)
Return an iterator for this widget.
Definition: image.cc:417
dw::core::style::isAbsLength
bool isAbsLength(Length l)
Returns true if l is an absolute length.
Definition: style.hh:403
dw::core::View::getClippingView
virtual View * getClippingView(int x, int y, int width, int height)=0
dw::core::Imgbuf
The platform independent interface for image buffers.
Definition: imgbuf.hh:161
dw::core::Requisition::width
int width
Definition: types.hh:174
dw::ImageMapsList::link
int link(lout::object::Object *key, int x, int y)
Definition: image.cc:130
dw::core::Shape
Abstract interface for different shapes.
Definition: types.hh:58
dw::core::Rectangle
dw::core::Shape implemtation for simple rectangles.
Definition: types.hh:69
dw::core::Imgbuf::unref
virtual void unref()=0
dw::Image::setBuffer
void setBuffer(core::Imgbuf *buffer, bool resize=false)
Called, when an image buffer is attached.
Definition: image.cc:424
dw::ImageMapsList::drawMap
void drawMap(lout::object::Object *key, core::View *view, core::style::Style *style, int x, int y)
Definition: image.cc:121
dw::ImageMapsList::setCurrentMapDefaultLink
void setCurrentMapDefaultLink(int link)
Set default link for current map-.
Definition: image.cc:116
lout::container::typed::List
Typed version of container::untyped::List.
Definition: container.hh:425
dw::core::View
An interface to encapsulate platform dependent drawing.
Definition: view.hh:16
dw::Image::fatal
void fatal()
Called, when there are problems with the retrieval of image data.
Definition: image.cc:464
dw::ImageMapsList
Represents a list of client-side image maps.
Definition: image.hh:23
lout::container::typed::Iterator::getNext
T * getNext()
Definition: container.hh:370
dw::core::Imgbuf::ref
virtual void ref()=0
dw::Image::motionNotifyImpl
bool motionNotifyImpl(core::EventMotion *event)
Definition: image.cc:293
dw::Image::contentY
int contentY(core::MousePositionEvent *event)
Definition: image.cc:285
dw::core::Shape::isPointWithin
virtual bool isPointWithin(int x, int y)=0
dw::Image::Image
Image(const char *altText)
Definition: image.cc:145
dw::ImageMapsList::ImageMapsList
ImageMapsList()
Definition: image.cc:77
dw::core::Allocation::ascent
int ascent
Definition: types.hh:168
dw::Image::finish
void finish()
Called, when all image data has been retrieved.
Definition: image.cc:459
dw::ImageMapsList::~ImageMapsList
~ImageMapsList()
Definition: image.cc:84
dw::ImageMapsList::ImageMap::draw
void draw(core::View *view, core::style::Style *style, int x, int y)
Definition: image.cc:42
dw
Dw is in this namespace, or sub namespaces of this one.
Definition: alignedtextblock.cc:26
dw::ImageMapsList::addShapeToCurrentMap
void addShapeToCurrentMap(core::Shape *shape, int link)
Add a shape to the current map-.
Definition: image.cc:108
dw::core::Rectangle::width
int width
Definition: types.hh:74
dw::ImageMapsList::startNewMap
void startNewMap(lout::object::Object *key)
Start a new map and make it the current one.
Definition: image.cc:96
dw::core::style::Style
Definition: style.hh:571
dw::core::Rectangle::y
int y
Definition: types.hh:73
dw::core::Allocation::width
int width
Definition: types.hh:167
dw::Image::CLASS_ID
static int CLASS_ID
Definition: image.hh:148