Esempio n. 1
0
void 
create_fgbz_chunk(IFFByteStream &iff)
{
  int nzones = g().colorzones.size();
  int npalette = g().colorpalette->size() / 3;
  GP<DjVuPalette> pal = DjVuPalette::create();
  g().colorpalette->seek(0);
  pal->decode_rgb_entries(*g().colorpalette, npalette);
  pal->colordata.resize(0,blit_count-1);
  for (int d=0; d<blit_count; d++)
    {
      JB2Blit *blit = g().stencil->get_blit(d);
      const JB2Shape &shape = g().stencil->get_shape(blit->shapeno);
      GRect brect(blit->left, blit->bottom, shape.bits->columns(), shape.bits->rows());
      int index = nzones;
      for (int i=0; i<nzones; i++)
        {
          GRect zrect = g().colorzones[i];
          if (zrect.isempty() || zrect.intersect(brect, zrect))
            index = i;
        }
      if (index >= npalette)
        G_THROW("create_fgbz_chunk: internal error");
      pal->colordata[d] = index;
    }
  iff.put_chunk("FGbz");
  pal->encode(iff.get_bytestream());
  iff.close_chunk();
}
void
QDBase::slotDisableDisplayAllHLinks(void)
{
   DEBUG_MSG("QDBase::slotDisableDisplayAllHLinks() called\n");
   DEBUG_MAKE_INDENT(3);

   try
   {
      if (!display_all_hlinks)
      {
	 DEBUG_MSG("already disabled => returning\n");
	 return;
      }

      GRect grect;
      grect.intersect(rectVisible, rectDocument);

	 // We want to hide here
      for(GPosition pos=map_areas;pos;++pos)
      {
	 GP<MapArea> ma=map_areas[pos];
	 ma->setForceAlwaysActive(false);
	 ma->setActive(false, true);
      }

      display_all_hlinks=0;
   } catch(const GException & exc)
   {
      showError(this, tr("DjVu Error"), exc);
   }
}
void
MapArea::drawOutline(const GRect & grect, QPainter * p_in)
{
   if (pane && mapper)
   {
      GRect brect=gmap_area->get_bound_rect();
      mapper->map(brect);
      brect.inflate(3, 3);
      GRect irect;
      if (irect.intersect(brect, grect))
      {
	 QPainter * p=p_in;
	 try
	 {
	    if (!p_in) p=new QPainter(pane);
	    else p_in->save();
	    p->setRasterOp(XorROP);
	    p->setPen(QColor(0xff, 0xff, 0xff));
	    p->setClipRect(G2Q(irect));
	    ma_drawOutline(p, irect);
	    if (editControlsEnabled()) drawEditControls(grect, p);
	    if (!p_in) { delete p; p=0; }
	    else p_in->restore();
	 } catch(...)
	 {
	    if (!p_in) delete p;
	    throw;
	 }
      }
   }
}
void
MapArea::setActive(bool on, bool redraw)
{
  if ((!on && isAlwaysActive()) || active==on)
    return;

  active=on;
  if (redraw && pane && mapper)
    {
      if (isActiveOutlineMode()) drawOutline(Q2G(pane->rect()));
      else if (!isCacheUsed())
	repaint();
      else
	{
	  // Use cache to draw ourselves
	  GRect brect=gmap_area->get_bound_rect();
	  mapper->map(brect);
	  brect.inflate(3, 3);
	  GRect pane_rect=Q2G(pane->rect());
	  GRect urect;
	  if (urect.intersect(pane_rect, brect))
	    {
	      for(GPosition pos=pieces;pos;++pos)
		{
		  GP<MapPiece> piece=pieces[pos];
		  GRect piece_rect=*piece;
		  mapper->map(piece_rect);
		  GRect irect;
		  if (irect.intersect(piece_rect, urect))
		    {
		      QPixmap & pix=active ? piece->getOnPixmap() : piece->getOffPixmap();
		      if (pix.isNull()) repaint(piece_rect);
		      QPainter p(pane);
		      GRect crect=doc_rect;
		      mapper->map(crect);
		      p.setClipRect(G2Q(crect));
		      p.drawPixmap(irect.xmin, irect.ymin, pix,
				   irect.xmin-piece_rect.xmin,
				   irect.ymin-piece_rect.ymin,
				   irect.width(), irect.height());
		    }
		}
	    }
	}
    }
}
void
MapRect::ma_drawInactive(const GRect & pm_rect, const GP<GPixmap> & pm)
      // pm_rect is the rectangle of the pane in screen coordinates
      // where pm is supposed to go to
{
   if (mapper && pm)
   {
      GRect border_rect=gmap_area->get_bound_rect();
      mapper->map(border_rect);

      GRect irect;
      if (irect.intersect(border_rect, pm_rect))
      {
	    // Translate the intersection into the GPixmap's coordinate
	 irect.translate(-pm_rect.xmin, -pm_rect.ymin);

	    // Do hiliting first
	 if (gmap_area->hilite_color!=0xffffffff)
	 {
	    if (gmap_area->hilite_color==0xff000000)
	    {
		  // Do XOR hiliting
	       for(int y=irect.ymin;y<irect.ymax;y++)
	       {
		  GPixel * pix=(*pm)[pm->rows()-1-y]+irect.xmin;
		  for(int x=irect.xmin;x<irect.xmax;x++, pix++)
		  {
		     pix->r^=0xff;
		     pix->g^=0xff;
		     pix->b^=0xff;
		  }
	       }
	    } else
	    {
		  // Do COLOR hiliting
	       int r=(gmap_area->hilite_color & 0xff0000) >> (16+2);
	       int g=(gmap_area->hilite_color & 0xff00) >> (8+2);
	       int b=(gmap_area->hilite_color & 0xff) >> 2;
	       for(int y=irect.ymin;y<irect.ymax;y++)
	       {
		  GPixel * pix=(*pm)[pm->rows()-1-y]+irect.xmin;
		  for(int x=irect.xmin;x<irect.xmax;x++, pix++)
		  {
		     pix->r=((((int) pix->r << 1)+(int) pix->r) >> 2)+r;
		     pix->g=((((int) pix->g << 1)+(int) pix->g) >> 2)+g;
		     pix->b=((((int) pix->b << 1)+(int) pix->b) >> 2)+b;
		  }
	       }
	    }
	 }
      }
void
MapArea::repaintPiece(const GP<MapPiece> & piece)
      // Sends PaintEvent to cause repaint of the specified piece
{
   if (pane && mapper)
   {
      GRect grect=*piece;
      mapper->map(grect);
      
      GRect prect=Q2G(pane->rect());
      GRect irect;
      if (irect.intersect(grect, prect)) repaint(irect);
   }
}
void
MapArea::repaint(void)
      // Generates PaintEvents for the whole area
{
   if (pane && mapper)
   {
      GRect brect=gmap_area->get_bound_rect();
      mapper->map(brect);
      brect.inflate(3, 3);	// Take into account possible edit controls

      GRect prect=Q2G(pane->rect());
      GRect irect;
      if (irect.intersect(brect, prect)) repaint(irect);
   }
}
void
MapArea::drawEditControls(const GRect & grect, QPainter * p_in)
      // grect is in the screen coord system
      // Correct painter modes WILL be set
{
   GRect brect=gmap_area->get_bound_rect();
   mapper->map(brect);
   brect.inflate(3, 3);
  
   GRect irect;
   if (irect.intersect(grect, brect))
   {
      QPainter * p=p_in;
      try
      {
	    // Prepare
	 if (!p_in) p=new QPainter(pane);
	 else p_in->save();
	 p->setRasterOp(XorROP);
	 p->setPen(QColor(0xff, 0xff, 0xff));
	 p->setClipRect(G2Q(irect));

	    // Draw
	 int xmin=brect.xmin+3, xmax=brect.xmax-3;
	 int ymin=brect.ymin+3, ymax=brect.ymax-3;
	 _drawFrame(*p, xmin-1, ymin-1, xmax+1, ymax+1, 10);
	 _drawFrame(*p, xmin-3, ymin-3, xmax+3, ymax+3, 12);      
	 ma_drawEditControls(p);

	    // Finish
	 if (!p_in) { delete p; p=0; }
	 else p_in->restore();
      } catch(...)
      {
	 if (!p_in) delete p;
	 throw;
      }
   }
}
void
QDBase::eraseMapAreas(bool search_results_too, bool allow_draw)
{
   DEBUG_MSG("QDBase::eraseMapAreas(): Erasing the map areas\n");
   DEBUG_MAKE_INDENT(3);

   GRect grect;
   grect.intersect(rectDocument, rectVisible);
   
   for(GPosition pos=map_areas;pos;)
   {
      GP<MapArea> ma=map_areas[pos];
      if (search_results_too || ma->getComment()!=search_results_name)
      {
	 GPosition this_pos=pos;
	 ++pos;
	 map_areas.del(this_pos);
	 
	 if (!grect.isempty() && allow_draw) ma->repaint();
      } else ++pos;
   }
   cur_map_area=0;
   delete map_area_tip; map_area_tip=0;
}
void
MapArea::draw(const GRect & bm_rect, const GP<GBitmap> & bm_in,
	      GRect & pm_rect, GP<GPixmap> & pm_out,
	      DRAW_MODE draw_mode)
      // Draws itself into the specified bitmap. The bm_rect should be
      // in the pane's coordinates. Since GBitmap may not contain color
      // information, we will create a color GPixmap patch (pm_out), where we
      // will actually be drawing. The pm_rect is a rectangle in
      // pane coordinates where this pm_out should go to.
{
   DEBUG_MSG("MapArea::draw(): Highlighting " << gmap_area->url << ":" <<
	     gmap_area->target << "\n");
   DEBUG_MAKE_INDENT(3);

   if (pane)
   {
      GRect brect=gmap_area->get_bound_rect();
      mapper->map(brect);
      brect.inflate(3, 3);
      
      GRect irect;
      if (irect.intersect(bm_rect, brect))
      {
	 pm_rect=irect;
	 irect.translate(-bm_rect.xmin, -bm_rect.ymin);
	 pm_out=GPixmap::create(*bm_in, GRect(irect.xmin, bm_in->rows()-irect.ymax,
					  irect.width(), irect.height()));
	 if (!isInactiveOutlineMode())
	    if (draw_mode==DRAW_INACTIVE || draw_mode==DRAW_ACTIVE)
	       ma_drawInactive(pm_rect, pm_out);
	 if (!isActiveOutlineMode())
	    if (draw_mode==APPLY_ACTIVE || draw_mode==DRAW_ACTIVE)
	       ma_applyActive(pm_rect, pm_out);
      }
   }
}
void
QDBase::layout(bool allow_redraw)
{
  DEBUG_MSG("QDBase::layout() called\n");
  DEBUG_MAKE_INDENT(3);
  
  if (in_layout)
    {
      DEBUG_MSG("but we seem to be already here => must be called because of resize\n");
      return;
    }

  IncFlag inc(&in_layout);
  
  // Obtain document size
  int doc_w=0;
  int doc_h=0;
  if (dimg)
    {
      doc_w=dimg->get_width();
      doc_h=dimg->get_height();
      if (doc_w>0 && doc_h>0) 
        image_size_known = 1;
    }
  
  if (!doc_w || !doc_h)
    {
      DEBUG_MSG("document rectangle is empty...just hide scroll bars\n");
      hscroll->hide();
      vscroll->hide();
      pane->resize(main_widget->width(), main_widget->height());
      return;
    }

  bool do_redraw = false;
  bool update_tbar = false;
  bool hscroll_visible = false;
  bool vscroll_visible = false;

  int toolbar_height = toolbar->computeHeight(main_widget->width());
  toolbar_enabled = (override_flags.toolbar && prefs.toolBarOn);
  if (toolbar_height + 2 * hscroll->height() > main_widget->height() )
    toolbar_enabled = 0;
  if (!isToolBarEnabled())
    toolbar_height = 0;
  else if (!isToolBarStuck())
    toolbar_height = toolbar_edge;
      
  bool fullscreen = false;
  emit sigQueryFullScreen(fullscreen);

  rectVisible = GRect(0, 0, main_widget->width(), main_widget->height()-toolbar_height);
  if (cmd_zoom==IDC_ZOOM_STRETCH)
    {
      do_redraw |= allow_redraw;
      rectDocument = rectVisible;
    } 
  else
    {
      // The scaling code can reduce the image *fast* 1, 2, 3, 4, 6 or 12 times
      // When "Favor fast magnifications for fast resolutions" is set,
      // we're forcing plugin to use these "fast" reductions.
      // Note, that the actual zoom factor (in %%) will depend on the
      // screen and image dpi.
      const int fast_red[]={ 1, 2, 3, 4, 6, 12 };
      const int fast_reds=sizeof(fast_red)/sizeof(fast_red[0]);
      int red_ind=0;
      float red=1/100000.0;
      while(true)	// Loop until we're sure about scrollbars and toolbar height
        {
          int image_dpi=300;
          if (dimg) image_dpi=dimg->get_rounded_dpi();
          if (image_dpi<=0 || image_dpi>=2400) image_dpi=300;
              
          DEBUG_MSG("displ_dpi=" << displ_dpi << ", image_dpi=" << image_dpi << "\n");
              
          // Compute reduction from cmd_zoom
          if (cmd_zoom>=IDC_ZOOM_MIN && cmd_zoom<=IDC_ZOOM_MAX)
            {
              // Fixed resolution
              int zoom=cmd_zoom-IDC_ZOOM_MIN;
              DEBUG_MSG("zoom=" << zoom << "%\n");
                  
              red=(float) image_dpi/zoom;
            } 
          else if (cmd_zoom==IDC_ZOOM_ONE2ONE)
            {
              red=1;
            } 
          else if (cmd_zoom==IDC_ZOOM_PAGE)
            {
              // IDC_ZOOM_PAGE case
              if (prefs.fastZoom)
                {
                  // We may continue to loop from the previous scroll bar iteration
                  for(;red_ind<fast_reds;red_ind++)
                    {
                      red=fast_red[red_ind];
                      if (doc_w<=rectVisible.width()*red &&
                          doc_h<=rectVisible.height()*red)
                        break;
                    }
                }
                  
              if (doc_w>rectVisible.width()*red ||
                  doc_h>rectVisible.height()*red)
                {
                  // Either we're not in the "fast" mode, or the
                  // capabilities of the "fast" mode are not sufficient
                  // to reduce the document so much
                  float red_w=(float) doc_w/rectVisible.width();
                  float red_h=(float) doc_h/rectVisible.height();
                  float red_new=red_w<red_h ? red_h : red_w;
                      
                  // The following is necessary to avoid infinite loop with
                  // appearing and disappearing scroll bars.
                  if (red_new>red) red=red_new;
                }
            } 
          else
            {
              // Make it IDC_ZOOM_WIDTH even if it's not
              if (prefs.fastZoom)
                {
                  // We may continue to loop from the previous scroll bar iteration
                  for(;red_ind<fast_reds;red_ind++)
                    {
                      red=fast_red[red_ind];
                      if (doc_w<=rectVisible.width()*red)
                        break;
                    }
                }
                  
              if (doc_w>rectVisible.width()*red)
                {
                  // Either we're not in the "fast" mode, or the
                  // capabilities of the "fast" mode are not sufficient
                  // to reduce the document so much
                  float red_new=(float) doc_w/rectVisible.width();
                      
                  // The following is necessary to avoid infinite loop with
                  // appearing and disappearing scroll bars.
                  if (red_new>red) red=red_new;
                }
            }
          DEBUG_MSG("reduction=" << red << ", scale factor=" << (1/red) << "\n");
              
          // determine scrollbar visibility and modify rectVisible
          rectVisible=GRect(0, 0, main_widget->width(),
                            main_widget->height()-toolbar_height);
          DEBUG_MSG("before engaging scrolls rectVisible=(" << rectVisible.xmin <<
                    ", " << rectVisible.ymin << ", " << rectVisible.width() <<
                    ", " << rectVisible.height() << ")\n");
          int sh = hscroll->height();
          int sw = vscroll->width();
          bool hs_vis=false, vs_vis=false;
          if (override_flags.scrollbars && !fullscreen && 
              rectVisible.height()>2*sh && rectVisible.width()>2*sw)
            {
              while(1)
                {
                  if (!hs_vis && doc_w>round(rectVisible.width()*red))
                    {
                      rectVisible.ymax=main_widget->height()-toolbar_height-sh;
                      hs_vis=true;
                    }
                  else if (!vs_vis && doc_h>round(rectVisible.height()*red))
                    {
                      rectVisible.xmax=main_widget->width()-sw;
                      vs_vis=true;
                    }
                  else
                    {
                      break;
                    }
                }
            }
          DEBUG_MSG("after engaging scrolls rectVisible=(" << rectVisible.xmin <<
                    ", " << rectVisible.ymin << ", " << rectVisible.width() <<
                    ", " << rectVisible.height() << ")\n");
              
          if (hs_vis==hscroll_visible && vs_vis==vscroll_visible)
            break;
              
          DEBUG_MSG("Looks like we need another pass thru resolutions:\n");
          DEBUG_MSG("hscroll_visible: was=" << hscroll_visible 
                    << ", now=" << hs_vis << "\n");
          DEBUG_MSG("vscroll_visible: was=" << vscroll_visible 
                    << ", now=" << vs_vis << "\n");
          hscroll_visible=hs_vis;
          vscroll_visible=vs_vis;
        }
          
      DEBUG_MSG("hscroll_visible=" << hscroll_visible <<
                ", vscroll_visible=" << vscroll_visible << "\n");
          
      GRect prevRectDocument=rectDocument;
          
          // Modify rectDocument maintaining document position
      if (round(rectDocument.width()*red)!=doc_w ||
          round(rectDocument.height()*red)!=doc_h)
        {
          if (!rectDocument.isempty())
            {
              GRect rect;
              rect.intersect(rectVisible, rectDocument);
              int cx=(rect.xmin+rect.xmax)/2-rectDocument.xmin;
              int cy=(rect.ymin+rect.ymax)/2-rectDocument.ymin;
              rectDocument.xmin=rectDocument.xmax
                =(int) (rectVisible.width()/2-cx*doc_w/
                        (red*rectDocument.width()));
              rectDocument.ymin=rectDocument.ymax
                =(int) (rectVisible.height()/2-cy*doc_h/
                        (red*rectDocument.height()));
            }
        }
          
      // Determine scaled document rectangle (adjusting xmin and ymin)
      rectDocument.xmax=rectDocument.xmin+round(doc_w/red);
      rectDocument.ymax=rectDocument.ymin+round(doc_h/red);
          
      if (isToolBarEnabled() && 
          (prevRectDocument.width()!=rectDocument.width() ||
           prevRectDocument.height()!=rectDocument.height()))
        update_tbar=true;	// Since getZoom() may now return different value
      if (prevRectDocument.width()!=rectDocument.width() ||
          prevRectDocument.height()!=rectDocument.height() ||
          prevRectDocument.xmin!=rectDocument.xmin ||
          prevRectDocument.ymin!=rectDocument.ymin)
        do_redraw|=allow_redraw;
          
      DEBUG_MSG("before aligning rectDocument=(" << 
                rectDocument.xmin << ", " << rectDocument.ymin << ", " <<
                rectDocument.width() << ", " << rectDocument.height() << ")\n");
          
      // adjust document location. Please note: there is a copy of this code in
      // Scroll(). If you make any changes, make sure to do it twice :)
      int xoff=0;
      int yoff=0;
          
      int hor_align=DjVuANT::ALIGN_CENTER;
      int ver_align=DjVuANT::ALIGN_CENTER;
      if (anno && anno->ant)
        {
          hor_align=anno->ant->hor_align;
          ver_align=anno->ant->ver_align;
        }
      if (override_flags.hor_align!=DjVuANT::ALIGN_UNSPEC)
        hor_align=override_flags.hor_align;
      if (override_flags.ver_align!=DjVuANT::ALIGN_UNSPEC)
        ver_align=override_flags.ver_align;
          
      if (rectDocument.width()<=rectVisible.width())
        {
          switch(hor_align)
            {
            case DjVuANT::ALIGN_LEFT:
              xoff=rectVisible.xmin-rectDocument.xmin;
              break;
            case DjVuANT::ALIGN_CENTER:
            case DjVuANT::ALIGN_UNSPEC:
              xoff=rectVisible.xmin-rectDocument.xmin+
                (rectVisible.width()-rectDocument.width())/2;
              break;
            case DjVuANT::ALIGN_RIGHT:
              xoff=rectVisible.xmax-rectDocument.xmax;
              break;
            }
        } 
      else if (rectDocument.xmin>rectVisible.xmin)
        xoff=rectVisible.xmin-rectDocument.xmin;
      else if (rectDocument.xmax<rectVisible.xmax)
        xoff=rectVisible.xmax-rectDocument.xmax;
          
      if (rectDocument.height()<=rectVisible.height())
        {
          switch(ver_align)
            {
            case DjVuANT::ALIGN_TOP:
              yoff=rectVisible.ymin-rectDocument.ymin;
              break;
            case DjVuANT::ALIGN_CENTER:
            case DjVuANT::ALIGN_UNSPEC:
              yoff=rectVisible.ymin-rectDocument.ymin+
                (rectVisible.height()-rectDocument.height())/2;
              break;
            case DjVuANT::ALIGN_BOTTOM:
              yoff=rectVisible.ymax-rectDocument.ymax;
              break;
            }
        } 
      else if (rectDocument.ymin>rectVisible.ymin)
        yoff=rectVisible.ymin-rectDocument.ymin;
      else if (rectDocument.ymax<rectVisible.ymax)
        yoff=rectVisible.ymax-rectDocument.ymax;
          
      if (rectDocument.width()>0 && rectDocument.height()>0)
        rectDocument.translate(xoff, yoff);
          
      DEBUG_MSG("translated rectDocument=(" << rectDocument.xmin << 
                ", " << rectDocument.ymin << ", " <<
                rectDocument.width() << ", " << rectDocument.height() << ")\n");
    }
      
  // Make the pane be on top so that any transient movements (of the
  // toolbar and scrollbars) will not cause any extra Expose events
  // TODO: RAISE: pane->raise();
      
      // Resize the pane and scroll bars
  if (hscroll_visible)
    {
      hscroll->move(0, rectVisible.height()+toolbar_height);
      hscroll->show();
    } 
  else 
    hscroll->hide();
  if (vscroll_visible)
    {
      vscroll->move(rectVisible.width(), 0);
      vscroll->show();
    } 
  else
    vscroll->hide();

      // Since QDPane is created with WResizeNoErase flag, we need to
      // redraw ourselves if the pane's size changed.
  if (pane->width()!=rectVisible.width() ||
      pane->height()!=rectVisible.height()) 
    do_redraw |= allow_redraw;
      
  pane->resize(rectVisible.width(), rectVisible.height());
  hscroll->resize(rectVisible.width(), hscroll->height());
  vscroll->resize(vscroll->width(), rectVisible.height()+toolbar_height);
      
  if (isToolBarEnabled())
    {
      toolbar->resize(rectVisible.width(), toolbar->height());
      toolbar->move(0, rectVisible.height());
      if (!isToolBarStuck() && isToolBarShown())
        {
          toolbar_shown=false;
          showToolBar(false);
        }
    } else if (toolbar)
      toolbar->move(0, main_widget->height());
      
      // Now, when everything is in place set the stacking order properly
  if (toolbar) toolbar->raise();
  hscroll->raise();
  vscroll->raise();
      
  // Adjust scroll bars parameters
  if (vscroll->isVisible())
    {
      int value, sliderSize;
      value=rectVisible.ymin-rectDocument.ymin;
      if (value<0) value=0;
      sliderSize=rectVisible.height()<rectDocument.height() ?
        rectVisible.height() : rectDocument.height();
      vscroll->setRange(0, rectDocument.height()-sliderSize);
      vscroll->setValue(value);
      vscroll->setSteps(rectDocument.height()/25, sliderSize);
    }
      
  if (hscroll->isVisible())
    {
      int value, sliderSize;
      value=rectVisible.xmin-rectDocument.xmin;
      if (value<0) value=0;
      sliderSize=rectVisible.width()<rectDocument.width() ?
        rectVisible.width() : rectDocument.width();
      hscroll->setRange(0, rectDocument.width()-sliderSize);
      hscroll->setValue(value);
      hscroll->setSteps(rectDocument.width()/25, sliderSize);
    }
      
  // Set rectangle mapper
  setMappers();
      
  for(GPosition pos=map_areas;pos;++pos)
    map_areas[pos]->layout(GRect(0, 0, dimg->get_width(), dimg->get_height()));
      
      // Resizing margin caches:
  bm_cache.resize(rectDocument.width(), rectDocument.height(),
                  rectVisible.width(), rectVisible.height());
  pm_cache.resize(rectDocument.width(), rectDocument.height(),
                  rectVisible.width(), rectVisible.height());
      
  if (do_redraw) redraw();
  if (update_tbar) updateToolBar();
      
  DEBUG_MSG("QDBase::layout(): DONE\n");
}
void
MapArea::updateCache(const GRect & pm_rect, const GP<GPixmap> & pm,
		     GRectMapper * sdoc_mapper)
      // Takes the passed pixmap and updated the internal cache.
      // The pixmap should already contain the hyperlink draw in the
      // INACTIVE state. We will copy it and apply ACTIVE part here.
      // pm_rect is a rectangle in pane's coordinates where pm is supposed
      // to go to. sdoc_mapper maps screen coordinates to the coordinates
      // of the scaled document (see qd_base_paint.cpp)
{
   DEBUG_MSG("MapArea::updateCache(): updating caches\n");
   DEBUG_MAKE_INDENT(3);

   if (!isCacheUsed() || !pm || !pane) return;
   
   GRect brect=gmap_area->get_bound_rect();
   mapper->map(brect);
   brect.inflate(3, 3);		// To take into account edit controls
      
   GRect urect;
   if (urect.intersect(pm_rect, brect))
   {
      for(GPosition pos=pieces;pos;++pos)
      {
	 GP<MapPiece> piece=pieces[pos];
	 GRect prect=*piece;
	 mapper->map(prect);
	 GRect irect;
	 if (irect.intersect(prect, urect))
	 {
	    if (piece->getOnPixmap().isNull() || piece->getOffPixmap().isNull())
	       piece->createPixmaps();

	    QPixmap & on_pix=piece->getOnPixmap();
	    QPixmap & off_pix=piece->getOffPixmap();

	       // Now I need to make a copy of the area to be cached.
	       // The problem is that I'll need to draw into the GPixmap
	       // and I don't want to spoil the original.
	    GP<GPixmap> ipix_off;
	    GRect pix_rect=irect;
	    pix_rect.translate(-pm_rect.xmin, -pm_rect.ymin);
	    ipix_off=GPixmap::create(*pm, GRect(pix_rect.xmin, pm->rows()-pix_rect.ymax,
					    pix_rect.width(), pix_rect.height()));
	    GP<GPixmap> ipix_on=GPixmap::create(*ipix_off);

	       // Now ipix_off and ipix_on contains the data, which can be modified.
	       // Draw the map area into them
	    draw(irect, ipix_on, APPLY_ACTIVE);

	       // Dither pix_off and pix_on
	    GRect drect=irect;
	    sdoc_mapper->map(drect);
	    if (qxImager)
              qxImager->dither(*ipix_on, drect.xmin, drect.ymin);
	    if (qxImager)
              qxImager->dither(*ipix_off, drect.xmin, drect.ymin);

	       // Now copy the GPixmaps into QPixmaps to be used for caching
	    QDPainter p_off(&off_pix);
	    p_off.drawPixmap(GRect(irect.xmin-prect.xmin,
				   irect.ymin-prect.ymin,
				   irect.width(), irect.height()), ipix_off);
	    p_off.end();
	    
	    QDPainter p_on(&on_pix);
	    p_on.drawPixmap(GRect(irect.xmin-prect.xmin,
				  irect.ymin-prect.ymin,
				  irect.width(), irect.height()), ipix_on);
	    p_on.end();
	 }
      }
   }
}