void ViewerNode::setPartialUpdateParams(const std::list<RectD>& rois, bool recenterViewer) { double viewerCenterX = 0; double viewerCenterY = 0; if (recenterViewer) { RectD bbox; bool bboxSet = false; for (std::list<RectD>::const_iterator it = rois.begin(); it != rois.end(); ++it) { if (!bboxSet) { bboxSet = true; bbox = *it; } else { bbox.merge(*it); } } viewerCenterX = (bbox.x1 + bbox.x2) / 2.; viewerCenterY = (bbox.y1 + bbox.y2) / 2.; } QMutexLocker k(&_imp->partialUpdatesMutex); _imp->partialUpdateRects = rois; _imp->viewportCenterSet = recenterViewer; _imp->viewportCenter.x = viewerCenterX; _imp->viewportCenter.y = viewerCenterY; }
RectI TrackMarker::getMarkerImageRoI(int time) const { const unsigned int mipmapLevel = 0; Point center, offset; KnobDoublePtr centerKnob = getCenterKnob(); KnobDoublePtr offsetKnob = getOffsetKnob(); center.x = centerKnob->getValueAtTime(time, 0); center.y = centerKnob->getValueAtTime(time, 1); offset.x = offsetKnob->getValueAtTime(time, 0); offset.y = offsetKnob->getValueAtTime(time, 1); RectD roiCanonical; KnobDoublePtr swBl = getSearchWindowBottomLeftKnob(); KnobDoublePtr swTr = getSearchWindowTopRightKnob(); roiCanonical.x1 = swBl->getValueAtTime(time, 0) + center.x + offset.x; roiCanonical.y1 = swBl->getValueAtTime(time, 1) + center.y + offset.y; roiCanonical.x2 = swTr->getValueAtTime(time, 0) + center.x + offset.x; roiCanonical.y2 = swTr->getValueAtTime(time, 1) + center.y + offset.y; RectI roi; NodePtr node = getContext()->getNode(); NodePtr input = node->getInput(0); if (!input) { return RectI(); } roiCanonical.toPixelEnclosing(mipmapLevel, input ? input->getEffectInstance()->getAspectRatio(-1) : 1., &roi); return roi; }
// caller must free() the result char *DestRectToStr(BaseEngine *engine, PageDestination *dest) { if (ScopedMem<WCHAR>(dest->GetDestName())) { ScopedMem<char> name(Escape(dest->GetDestName())); return str::Format("Name=\"%s\"", name); } // as handled by LinkHandler::ScrollTo in WindowInfo.cpp int pageNo = dest->GetDestPageNo(); if (pageNo <= 0 || pageNo > engine->PageCount()) return NULL; RectD rect = dest->GetDestRect(); if (rect.IsEmpty()) { PointD pt = engine->Transform(rect.TL(), pageNo, 1.0, 0); return str::Format("Point=\"%.0f %.0f\"", pt.x, pt.y); } if (rect.dx != DEST_USE_DEFAULT && rect.dy != DEST_USE_DEFAULT) { RectI rc = engine->Transform(rect, pageNo, 1.0, 0).Round(); return str::Format("Rect=\"%d %d %d %d\"", rc.x, rc.y, rc.dx, rc.dy); } if (rect.y != DEST_USE_DEFAULT) { PointD pt = engine->Transform(rect.TL(), pageNo, 1.0, 0); return str::Format("Point=\"x %.0f\"", pt.y); } return NULL; }
// get the coordinates of a specific tile static RectI GetTileRectDevice(BaseEngine* engine, int pageNo, int rotation, float zoom, TilePosition tile) { RectD mediabox = engine->PageMediabox(pageNo); if (tile.res > 0 && tile.res != INVALID_TILE_RES) mediabox = GetTileRect(mediabox, tile); RectD pixelbox = engine->Transform(mediabox, pageNo, zoom, rotation); return pixelbox.Round(); }
void XARGenerator::DetermineLinearGradientPoints(const Gradient* pGradient, const Transformation& trans, const RectD& boundings, DocCoord& p1, DocCoord& p2) { if (pGradient->units == Gradient::ObjectBoundingBox) { PointD pLower = boundings.LowerCoord(); PointD pHigher = boundings.HigherCoord(); p1 = DocCoord((INT32)pLower.x, m_docSize.y - (INT32)pLower.y); p2 = DocCoord((INT32)pHigher.x, m_docSize.y - (INT32)pHigher.y); #ifdef SVGDEBUG svgtrace(DBGTRACE_GRADIENTS, "using ObjectBoundingBox %d,%d %d,%d\n", p1.x, p1.y, p2.x, p2.y); #endif } else { // Gradient->units == Gradient::UserSpaceOnUse double fX1 = pGradient->x1; double fY1 = pGradient->y1; double fX2 = pGradient->x2; double fY2 = pGradient->y2; trans.ApplyToCoordinate(fX1, fY1, &fX1, &fY1); trans.ApplyToCoordinate(fX2, fY2, &fX2, &fY2); p1 = DocCoord((INT32)fX1, m_docSize.y - (INT32)fY1); p2 = DocCoord((INT32)fX2, m_docSize.y - (INT32)fY2); #if SVGDEBUG svgtrace(DBGTRACE_GRADIENTS, "using UserSpaceOnUse %d,%d %d,%d\n", p1.x, p1.y, p2.x, p2.y); #endif } }
static LRESULT OnPaint(HWND hwnd) { ClientRect rect(hwnd); DoubleBuffer buffer(hwnd, rect); HDC hdc = buffer.GetDC(); HBRUSH brushBg = CreateSolidBrush(COL_WINDOW_BG); HBRUSH brushWhite = GetStockBrush(WHITE_BRUSH); FillRect(hdc, &rect.ToRECT(), brushBg); PreviewBase *preview = (PreviewBase *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (preview && preview->renderer) { int pageNo = GetScrollPos(hwnd, SB_VERT); RectD page = preview->renderer->GetPageRect(pageNo); if (!page.IsEmpty()) { rect.Inflate(-PREVIEW_MARGIN, -PREVIEW_MARGIN); float zoom = (float)min(rect.dx / page.dx, rect.dy / page.dy) - 0.001f; RectI onScreen = RectD(rect.x, rect.y, page.dx * zoom, page.dy * zoom).Round(); onScreen.Offset((rect.dx - onScreen.dx) / 2, (rect.dy - onScreen.dy) / 2); FillRect(hdc, &onScreen.ToRECT(), brushWhite); preview->renderer->Render(hdc, onScreen, pageNo, zoom); } } DeleteObject(brushBg); DeleteObject(brushWhite); PAINTSTRUCT ps; buffer.Flush(BeginPaint(hwnd, &ps)); EndPaint(hwnd, &ps); return 0; }
void DumpThumbnail(BaseEngine *engine) { RectD rect = engine->Transform(engine->PageMediabox(1), 1, 1.0, 0); if (rect.IsEmpty()) { Out("\t<Thumbnail />\n"); return; } float zoom = min(128 / (float)rect.dx, 128 / (float)rect.dy) - 0.001f; RectI thumb = RectD(0, 0, rect.dx * zoom, rect.dy * zoom).Round(); rect = engine->Transform(thumb.Convert<double>(), 1, zoom, 0, true); RenderedBitmap *bmp = engine->RenderBitmap(1, zoom, 0, &rect); if (!bmp) { Out("\t<Thumbnail />\n"); return; } size_t len; ScopedMem<unsigned char> data(tga::SerializeBitmap(bmp->GetBitmap(), &len)); ScopedMem<char> hexData(data ? str::MemToHex(data, len) : NULL); if (hexData) Out("\t<Thumbnail>\n\t\t%s\n\t</Thumbnail>\n", hexData.Get()); else Out("\t<Thumbnail />\n"); delete bmp; }
static RectD BoundSelectionOnPage(const Vec<SelectionOnPage> &sel, int pageNo) { RectD bounds; for (size_t i = 0; i < sel.Count(); i++) { if (sel.At(i).pageNo == pageNo) bounds = bounds.Union(sel.At(i).rect); } return bounds; }
void DjVuEngineImpl::AddUserAnnots(RenderedBitmap *bmp, int pageNo, float zoom, int rotation, RectI screen) { if (!bmp || userAnnots.Count() == 0) return; HDC hdc = CreateCompatibleDC(NULL); HGDIOBJ prevBmp = SelectObject(hdc, bmp->GetBitmap()); { using namespace Gdiplus; Graphics g(hdc); g.SetCompositingQuality(CompositingQualityHighQuality); g.SetPageUnit(UnitPixel); for (size_t i = 0; i < userAnnots.Count(); i++) { PageAnnotation& annot = userAnnots.At(i); if (annot.pageNo != pageNo) continue; RectD arect; switch (annot.type) { case Annot_Highlight: arect = Transform(annot.rect, pageNo, zoom, rotation); arect.Offset(-screen.x, -screen.y); g.FillRectangle(&SolidBrush(Unblend(annot.color, 119)), arect.ToGdipRectF()); break; case Annot_Underline: case Annot_StrikeOut: arect = RectD(annot.rect.x, annot.rect.BR().y, annot.rect.dx, 0); if (Annot_StrikeOut == annot.type) arect.y -= annot.rect.dy / 2; arect = Transform(arect, pageNo, zoom, rotation); arect.Offset(-screen.x, -screen.y); g.DrawLine(&Pen(FromColor(annot.color), zoom), (float)arect.x, (float)arect.y, (float)arect.BR().x, (float)arect.BR().y); break; case Annot_Squiggly: { Pen p(FromColor(annot.color), 0.5f * zoom); REAL dash[2] = { 2, 2 }; p.SetDashPattern(dash, dimof(dash)); p.SetDashOffset(1); arect = Transform(RectD(annot.rect.x, annot.rect.BR().y - 0.25f, annot.rect.dx, 0), pageNo, zoom, rotation); arect.Offset(-screen.x, -screen.y); g.DrawLine(&p, (float)arect.x, (float)arect.y, (float)arect.BR().x, (float)arect.BR().y); p.SetDashOffset(3); arect = Transform(RectD(annot.rect.x, annot.rect.BR().y + 0.25f, annot.rect.dx, 0), pageNo, zoom, rotation); arect.Offset(-screen.x, -screen.y); g.DrawLine(&p, (float)arect.x, (float)arect.y, (float)arect.BR().x, (float)arect.BR().y); } break; } } } SelectObject(hdc, prevBmp); DeleteDC(hdc); }
void ViewerGL::Implementation::getPolygonTextureCoordinates(const QPolygonF & polygonPoints, const RectD & texRect, QPolygonF & texCoords) { texCoords.resize( polygonPoints.size() ); for (int i = 0; i < polygonPoints.size(); ++i) { const QPointF & polygonPoint = polygonPoints.at(i); QPointF texCoord; texCoord.setX( (polygonPoint.x() - texRect.x1) / texRect.width() ); // * (right - left)); texCoord.setY( (polygonPoint.y() - texRect.y1) / texRect.height() ); // * (top - bottom)); texCoords[i] = texCoord; } }
// The offset of the current project in canonical coordinates. // The offset is related to the kOfxImageEffectPropProjectSize and is the offset from the origin // of the project 'subwindow'. For example for a PAL SD project that is in letterbox form, the // project offset is the offset to the bottom left hand corner of the letter box. The project // offset is in canonical coordinates. void OfxImageEffectInstance::getProjectOffset(double & xOffset, double & yOffset) const { Format f; _ofxEffectInstance->getRenderFormat(&f); RectI pixelF; pixelF.x1 = f.x1; pixelF.x2 = f.x2; pixelF.y1 = f.y1; pixelF.y2 = f.y2; RectD canonicalF; pixelF.toCanonical_noClipping(0, f.getPixelAspectRatio(), &canonicalF); xOffset = canonicalF.left(); yOffset = canonicalF.bottom(); }
// The extent of the current project in canonical coordinates. // The extent is the size of the 'output' for the current project. See ProjectCoordinateSystems // for more infomation on the project extent. The extent is in canonical coordinates and only // returns the top right position, as the extent is always rooted at 0,0. For example a PAL SD // project would have an extent of 768, 576. void OfxImageEffectInstance::getProjectExtent(double & xSize, double & ySize) const { Format f; _ofxEffectInstance->getRenderFormat(&f); RectI pixelF; pixelF.x1 = f.x1; pixelF.x2 = f.x2; pixelF.y1 = f.y1; pixelF.y2 = f.y2; RectD canonicalF; pixelF.toCanonical_noClipping(0, f.getPixelAspectRatio(), &canonicalF); xSize = canonicalF.right(); ySize = canonicalF.top(); }
std::pair<ImagePtr, RectD> TrackMarker::getMarkerImage(TimeValue time, const RectD& roi) const { assert( !roi.isNull() ); NodePtr node = getModel()->getNode(); NodePtr input = node->getInput(0); if (!input) { return std::make_pair(ImagePtr(), roi); } TreeRender::CtorArgsPtr args(new TreeRender::CtorArgs); { args->treeRootEffect = input->getEffectInstance(); args->time = time; args->view = ViewIdx(0); // Render default plane args->plane = 0; args->mipMapLevel = 0; args->proxyScale = RenderScale(1.); args->canonicalRoI = &roi; args->draftMode = false; args->playback = false; args->byPassCache = false; } TreeRenderPtr render = TreeRender::create(args); FrameViewRequestPtr outputRequest; ActionRetCodeEnum stat = render->launchRender(&outputRequest); if (isFailureRetCode(stat)) { return std::make_pair(ImagePtr(), roi); } ImagePtr sourceImage = outputRequest->getRequestedScaleImagePlane(); // Make sure the Natron image rendered is RGBA full rect and on CPU, we don't support other formats if (sourceImage->getStorageMode() != eStorageModeRAM) { Image::InitStorageArgs initArgs; initArgs.bounds = sourceImage->getBounds(); initArgs.plane = sourceImage->getLayer(); initArgs.bufferFormat = eImageBufferLayoutRGBAPackedFullRect; initArgs.storage = eStorageModeRAM; initArgs.bitdepth = sourceImage->getBitDepth(); ImagePtr tmpImage = Image::create(initArgs); if (!tmpImage) { return std::make_pair(ImagePtr(), roi); } Image::CopyPixelsArgs cpyArgs; cpyArgs.roi = initArgs.bounds; tmpImage->copyPixels(*sourceImage, cpyArgs); sourceImage = tmpImage; } return std::make_pair(sourceImage, roi); } // TrackMarker::getMarkerImage
// get the coordinates of a specific tile static RectI GetTileRectDevice(BaseEngine *engine, int pageNo, int rotation, float zoom, TilePosition tile) { RectD mediabox = engine->PageMediabox(pageNo); if (tile.res && tile.res != INVALID_TILE_RES) { CrashIf(tile.res > 30); double width = mediabox.dx / (1ULL << tile.res); mediabox.x += tile.col * width; mediabox.dx = width; double height = mediabox.dy / (1ULL << tile.res); mediabox.y += ((1 << tile.res) - tile.row - 1) * height; mediabox.dy = height; } RectD pixelbox = engine->Transform(mediabox, pageNo, zoom, rotation); return pixelbox.Round(); }
void Double_Knob::normalize(int dimension, double time, double* value) const { EffectInstance* effect = dynamic_cast<EffectInstance*>( getHolder() ); assert(effect); if (!effect) { // coverity[dead_error_line] return; } RectD rod; getInputRoD(effect,time,rod); if (dimension == 0) { *value /= rod.width(); } else if (dimension == 1) { *value /= rod.height(); } }
bool GetInvalidateRect(RectD & retVal) const { if (!m_invalidateRect.IsEmptyArea()) retVal = m_invalidateRect; if (m_hotItem) { if (hpcc::ElementG * hotElementG = GetElementG(m_hotItem)) { retVal = hotElementG->GetBoundingBox(); if (m_hotEdge) { if (hpcc::ElementG * hotElementG = GetElementG(m_hotEdge->GetFromVertex())) retVal.Union(hotElementG->GetBoundingBox()); if (hpcc::ElementG * hotElementG = GetElementG(m_hotEdge->GetToVertex())) retVal.Union(hotElementG->GetBoundingBox()); } else if(m_hotVertex) { for(IEdgeSet::const_iterator itr = m_hotVertex->GetInEdges().begin(); itr != m_hotVertex->GetInEdges().end(); ++itr) { if (hpcc::ElementG * hotElementG = GetElementG(itr->get())) retVal.Union(hotElementG->GetBoundingBox()); } for(IEdgeSet::const_iterator itr = m_hotVertex->GetOutEdges().begin(); itr != m_hotVertex->GetOutEdges().end(); ++itr) { if (hpcc::ElementG * hotElementG = GetElementG(itr->get())) retVal.Union(hotElementG->GetBoundingBox()); } } } } m_invalidateRect = retVal; return !m_invalidateRect.IsEmptyArea(); }
ActionRetCodeEnum RotoShapeRenderNode::isIdentity(TimeValue time, const RenderScale & scale, const RectI & roi, ViewIdx view, const ImagePlaneDesc& /*plane*/, TimeValue* inputTime, ViewIdx* inputView, int* inputNb, ImagePlaneDesc* /*inputPlane*/) { *inputView = view; NodePtr node = getNode(); *inputNb = -1; RotoDrawableItemPtr rotoItem = getAttachedRotoItem(); if (!rotoItem) { return eActionStatusFailed; } Bezier* isBezier = dynamic_cast<Bezier*>(rotoItem.get()); if (!rotoItem || !rotoItem->isActivated(time, view) || (isBezier && ((!isBezier->isCurveFinished(view) && !isBezier->isOpenBezier()) || isBezier->getControlPointsCount(view) <= 1))) { *inputTime = time; *inputNb = 0; return eActionStatusOK; } bool isPainting = isDuringPaintStrokeCreation(); RectD maskRod; getRoDFromItem(rotoItem, time, view, isPainting, &maskRod); RectI maskPixelRod; maskRod.toPixelEnclosing(scale, getAspectRatio(-1), &maskPixelRod); if ( !maskPixelRod.intersects(roi) ) { *inputTime = time; *inputNb = 0; } return eActionStatusOK; } // isIdentity
GRAPHDB_API ElementG * GetElementG(IGraphItem * item) { CUnknown * tmpProp = item->GetPropertyCUnknown(hpcc::SVG_PROP_ELEMENTG); if (tmpProp) return reinterpret_cast<hpcc::ElementG * >(tmpProp); RectD boundingBox; if (const ICluster * cluster = dynamic_cast<const ICluster *>(item)) // Not all layouts support clusters! { bool first = true; for(IClusterSet::const_iterator itr = cluster->GetClusters().begin(); itr != cluster->GetClusters().end(); ++itr) { ElementGPtr elementG = GetElementG(*itr); if (first) { first = false; boundingBox = elementG->GetBoundingBox(); } else boundingBox.Union(elementG->GetBoundingBox()); } for(IVertexSet::const_iterator itr = cluster->GetVertices().begin(); itr != cluster->GetVertices().end(); ++itr) { ElementGPtr elementG = GetElementG(*itr); if (first) { first = false; boundingBox = elementG->GetBoundingBox(); } else boundingBox.Union(elementG->GetBoundingBox()); } } ElementGPtr elementG = new ElementG(boundingBox); item->SetProperty(SVG_PROP_ELEMENTG, elementG); return elementG; }
void LinkHandler::ScrollTo(PageDestination *dest) { assert(owner && owner->linkHandler == this); int pageNo = dest->GetDestPageNo(); if (pageNo <= 0) return; if (owner->dm->AsChmEngine()) { owner->dm->AsChmEngine()->GoToDestination(dest); return; } DisplayModel *dm = owner->dm; PointI scroll(-1, 0); RectD rect = dest->GetDestRect(); if (rect.IsEmpty()) { // PDF: /XYZ top left // scroll to rect.TL() PointD scrollD = dm->engine->Transform(rect.TL(), pageNo, dm->ZoomReal(), dm->Rotation()); scroll = scrollD.Convert<int>(); // default values for the coordinates mean: keep the current position if (DEST_USE_DEFAULT == rect.x) scroll.x = -1; if (DEST_USE_DEFAULT == rect.y) { PageInfo *pageInfo = dm->GetPageInfo(dm->CurrentPageNo()); scroll.y = -(pageInfo->pageOnScreen.y - dm->GetWindowMargin()->top); scroll.y = max(scroll.y, 0); // Adobe Reader never shows the previous page } } else if (rect.dx != DEST_USE_DEFAULT && rect.dy != DEST_USE_DEFAULT) { // PDF: /FitR left bottom right top RectD rectD = dm->engine->Transform(rect, pageNo, dm->ZoomReal(), dm->Rotation()); scroll = rectD.TL().Convert<int>(); // Rect<float> rectF = dm->engine->Transform(rect, pageNo, 1.0, dm->rotation()).Convert<float>(); // zoom = 100.0f * min(owner->canvasRc.dx / rectF.dx, owner->canvasRc.dy / rectF.dy); } else if (rect.y != DEST_USE_DEFAULT) { // PDF: /FitH top or /FitBH top PointD scrollD = dm->engine->Transform(rect.TL(), pageNo, dm->ZoomReal(), dm->Rotation()); scroll.y = max(scrollD.Convert<int>().y, 0); // Adobe Reader never shows the previous page // zoom = FitBH ? ZOOM_FIT_CONTENT : ZOOM_FIT_WIDTH } // else if (Fit || FitV) zoom = ZOOM_FIT_PAGE // else if (FitB || FitBV) zoom = ZOOM_FIT_CONTENT /* // ignore author-set zoom settings (at least as long as there's no way to overrule them) if (zoom != INVALID_ZOOM) { // TODO: adjust the zoom level before calculating the scrolling coordinates dm->zoomTo(zoom); UpdateToolbarState(owner); } // */ dm->GoToPage(pageNo, scroll.y, true, scroll.x); }
bool XARGenerator::OutputEllipseEntity(const Style& style, const Transformation& trans, const RectD& r) { bool ok = true; if (r.IsUpright()) ok = OutputUprightEllipse(r); else ok = OutputComplexEllipse(r); /***/ ok = m_pExporter->WriteZeroSizedRecord(TAG_DOWN); OutputStyles(style, trans, r, STYLE_FILL_ALL|STYLE_STROKE_ALL|STYLE_OPACITY); /***/ ok = m_pExporter->WriteZeroSizedRecord(TAG_UP); return ok; }
RectD ImagesEngine::Transform(RectD rect, int pageNo, float zoom, int rotation, bool inverse) { PointF pts[2] = { PointF((REAL)rect.x, (REAL)rect.y), PointF((REAL)(rect.x + rect.dx), (REAL)(rect.y + rect.dy)) }; Matrix m; GetTransform(m, pageNo, zoom, rotation); if (inverse) m.Invert(); m.TransformPoints(pts, 2); rect = RectD::FromXY(pts[0].X, pts[0].Y, pts[1].X, pts[1].Y); // try to undo rounding errors caused by a rotation // (necessary correction determined by experimentation) if (rotation != 0) rect.Inflate(-0.01, -0.01); return rect; }
void AnimationModuleViewPrivate::keyFramesWithinRect(const RectD& canonicalRect, AnimItemDimViewKeyFramesMap* keys) const { // always running in the main thread assert( qApp && qApp->thread() == QThread::currentThread() ); if (canonicalRect.isNull()) { return; } std::vector<CurveGuiPtr> curves = getVisibleCurves(); for (std::vector<CurveGuiPtr>::const_iterator it = curves.begin(); it != curves.end(); ++it) { KeyFrameSet set = (*it)->getKeyFrames(); if ( set.empty() ) { continue; } AnimItemDimViewIndexID curveID = (*it)->getCurveID(); StringAnimationManagerPtr stringAnim = curveID.item->getInternalAnimItem()->getStringAnimation(); KeyFrameWithStringSet outKeys; for ( KeyFrameSet::const_iterator it2 = set.begin(); it2 != set.end(); ++it2) { double y = it2->getValue(); double x = it2->getTime(); if ( (x <= canonicalRect.x2) && (x >= canonicalRect.x1) && (y <= canonicalRect.y2) && (y >= canonicalRect.y1) ) { //KeyPtr newSelectedKey( new SelectedKey(*it, *it2, hasPrev, prevKey, hasNext, nextKey) ); KeyFrameWithString k; k.key = *it2; if (stringAnim) { stringAnim->stringFromInterpolatedIndex(it2->getValue(), curveID.view, &k.string); } outKeys.insert(k); } } if (!outKeys.empty()) { (*keys)[curveID] = outKeys; } } } // CurveWidgetPrivate::keyFramesWithinRect
bool GetPrevInvalidateRect(RectD & retVal) const { bool first = true; for (CGraphHotItemMap::const_iterator itr = m_prevSelected.begin(); itr != m_prevSelected.end(); ++itr) { if (first) { first = false; itr->second.GetInvalidateRect(retVal); } else { RectD rect; itr->second.GetInvalidateRect(rect); retVal.Union(rect); } } return true; }
bool XARGenerator::OutputRectEntity(const Style& style, const Transformation& trans, const RectD& r, double fRoundAxis) { bool ok = true; #if SVGDEBUG svgtrace(DBGTRACE_SHAPES, "rect: x1=%.2f y1=%.2f x2=%.2f y2=%.2f\n", r.p11.x, r.p11.y, r.p22.x, r.p22.y); #endif if (r.IsUpright()) OutputUprightRect(r, fRoundAxis); else OutputComplexRect(r, fRoundAxis); /***/ ok = m_pExporter->WriteZeroSizedRecord(TAG_DOWN); OutputStyles(style, trans, r, STYLE_FILL_ALL|STYLE_STROKE_ALL|STYLE_OPACITY); /***/ ok = m_pExporter->WriteZeroSizedRecord(TAG_UP); return ok; }
// 0___1___2___3 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 4---5---6----7 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 8---9--10--11 // | /| /| /| // | / | / | / | // |/ |/ |/ | // 12--13--14--15 void ViewerGL::Implementation::drawRenderingVAO(unsigned int mipMapLevel, int textureIndex, ViewerGL::DrawPolygonModeEnum polygonMode, bool background) { // always running in the main thread assert( qApp && qApp->thread() == QThread::currentThread() ); assert( QGLContext::currentContext() == _this->context() ); bool useShader = _this->getBitDepth() != eImageBitDepthByte; ///the texture rectangle in image coordinates. The values in it are multiples of tile size. /// const TextureRect &roiRounded = this->displayTextures[textureIndex].texture->getTextureRect(); const TextureRect& roiNotRounded = this->displayTextures[textureIndex].roiNotRoundedToTileSize; ///This is the coordinates in the image being rendered where datas are valid, this is in pixel coordinates ///at the time we initialize it but we will convert it later to canonical coordinates. See 1) const double par = roiRounded.par; RectD canonicalRoIRoundedToTileSize; roiRounded.toCanonical_noClipping(mipMapLevel, par /*, rod*/, &canonicalRoIRoundedToTileSize); RectD canonicalRoINotRounded; roiNotRounded.toCanonical_noClipping(mipMapLevel, par, &canonicalRoINotRounded); ///the RoD of the image in canonical coords. RectD rod = _this->getRoD(textureIndex); bool clipToDisplayWindow; { QMutexLocker l(&this->clipToDisplayWindowMutex); clipToDisplayWindow = this->clipToDisplayWindow; } RectD rectClippedToRoI(canonicalRoIRoundedToTileSize); rectClippedToRoI.intersect(rod, &rectClippedToRoI); if (clipToDisplayWindow) { RectD canonicalProjectFormat; this->getProjectFormatCanonical(canonicalProjectFormat); rod.intersect(canonicalProjectFormat, &rod); rectClippedToRoI.intersect(canonicalProjectFormat, &rectClippedToRoI); } //if user RoI is enabled, clip the rod to that roi bool userRoiEnabled; { QMutexLocker l(&this->userRoIMutex); userRoiEnabled = this->userRoIEnabled; } ////The texture real size (r.w,r.h) might be slightly bigger than the actual ////pixel coordinates bounds r.x1,r.x2 r.y1 r.y2 because we clipped these bounds against the bounds ////in the ViewerInstance::renderViewer function. That means we need to draw actually only the part of ////the texture that contains the bounds. ////Notice that r.w and r.h are scaled to the closest Po2 of the current scaling factor, so we need to scale it up ////So it is in the same coordinates as the bounds. ///Edit: we no longer divide by the closestPo2 since the viewer now computes images at lower resolution by itself, the drawing ///doesn't need to be scaled. if (userRoiEnabled) { { QMutexLocker l(&this->userRoIMutex); //if the userRoI isn't intersecting the rod, just don't render anything if ( !rod.intersect(this->userRoI, &rod) ) { return; } } rectClippedToRoI.intersect(rod, &rectClippedToRoI); //clipTexCoords<RectD>(canonicalTexRect,rectClippedToRoI,texBottom,texTop,texLeft,texRight); } if (polygonMode != eDrawPolygonModeWhole) { /// draw only the plane defined by the wipe handle QPolygonF polygonPoints, polygonTexCoords; RectD floatRectClippedToRoI; floatRectClippedToRoI.x1 = rectClippedToRoI.x1; floatRectClippedToRoI.y1 = rectClippedToRoI.y1; floatRectClippedToRoI.x2 = rectClippedToRoI.x2; floatRectClippedToRoI.y2 = rectClippedToRoI.y2; Implementation::WipePolygonEnum polyType = this->getWipePolygon(floatRectClippedToRoI, polygonMode == eDrawPolygonModeWipeRight, &polygonPoints); if (polyType == Implementation::eWipePolygonEmpty) { ///don't draw anything return; } else if (polyType == Implementation::eWipePolygonPartial) { this->getPolygonTextureCoordinates(polygonPoints, canonicalRoIRoundedToTileSize, polygonTexCoords); this->bindTextureAndActivateShader(textureIndex, useShader); GL_GPU::glBegin(GL_POLYGON); for (int i = 0; i < polygonTexCoords.size(); ++i) { const QPointF & tCoord = polygonTexCoords[i]; const QPointF & vCoord = polygonPoints[i]; GL_GPU::glTexCoord2d( tCoord.x(), tCoord.y() ); GL_GPU::glVertex2d( vCoord.x(), vCoord.y() ); } GL_GPU::glEnd(); this->unbindTextureAndReleaseShader(useShader); } else { ///draw the all polygon as usual polygonMode = eDrawPolygonModeWhole; } } if (polygonMode == eDrawPolygonModeWhole) { const double pixelCenterOffset = 0.5; // draw vertices at the center of the first and last pixel in the texture, with the same texture coordinates rectClippedToRoI.x1 += pixelCenterOffset * par; rectClippedToRoI.x2 -= pixelCenterOffset * par; rectClippedToRoI.y1 += pixelCenterOffset; rectClippedToRoI.y2 -= pixelCenterOffset; ///Vertices are in canonical coords GLfloat vertices[32] = { (GLfloat)rod.left(), (GLfloat)rod.top(), //0 (GLfloat)rectClippedToRoI.x1 + pixelCenterOffset, (GLfloat)rod.top(), //1 (GLfloat)rectClippedToRoI.x2 - pixelCenterOffset, (GLfloat)rod.top(), //2 (GLfloat)rod.right(), (GLfloat)rod.top(), //3 (GLfloat)rod.left(), (GLfloat)rectClippedToRoI.y2 - pixelCenterOffset, //4 (GLfloat)rectClippedToRoI.x1, (GLfloat)rectClippedToRoI.y2, //5 (GLfloat)rectClippedToRoI.x2, (GLfloat)rectClippedToRoI.y2, //6 (GLfloat)rod.right(), (GLfloat)rectClippedToRoI.y2, //7 (GLfloat)rod.left(), (GLfloat)rectClippedToRoI.y1, //8 (GLfloat)rectClippedToRoI.x1, (GLfloat)rectClippedToRoI.y1, //9 (GLfloat)rectClippedToRoI.x2, (GLfloat)rectClippedToRoI.y1, //10 (GLfloat)rod.right(), (GLfloat)rectClippedToRoI.y1, //11 (GLfloat)rod.left(), (GLfloat)rod.bottom(), //12 (GLfloat)rectClippedToRoI.x1, (GLfloat)rod.bottom(), //13 (GLfloat)rectClippedToRoI.x2, (GLfloat)rod.bottom(), //14 (GLfloat)rod.right(), (GLfloat)rod.bottom() //15 }; // GLfloat texBottom = 0; // GLfloat texTop = (GLfloat)(r.y2 - r.y1) / (GLfloat)(r.h /** r.closestPo2*/); // GLfloat texLeft = 0; // GLfloat texRight = (GLfloat)(r.x2 - r.x1) / (GLfloat)(r.w /** r.closestPo2*/); GLfloat texBottom = (GLfloat)(rectClippedToRoI.y1 - canonicalRoIRoundedToTileSize.y1) / canonicalRoIRoundedToTileSize.height(); GLfloat texTop = (GLfloat)(rectClippedToRoI.y2 - canonicalRoIRoundedToTileSize.y1) / canonicalRoIRoundedToTileSize.height(); GLfloat texLeft = (GLfloat)(rectClippedToRoI.x1 - canonicalRoIRoundedToTileSize.x1) / canonicalRoIRoundedToTileSize.width(); GLfloat texRight = (GLfloat)(rectClippedToRoI.x2 - canonicalRoIRoundedToTileSize.x1) / canonicalRoIRoundedToTileSize.width(); GLfloat renderingTextureCoordinates[32] = { texLeft, texTop, //0 texLeft, texTop, //1 texRight, texTop, //2 texRight, texTop, //3 texLeft, texTop, //4 texLeft, texTop, //5 texRight, texTop, //6 texRight, texTop, //7 texLeft, texBottom, //8 texLeft, texBottom, //9 texRight, texBottom, //10 texRight, texBottom, //11 texLeft, texBottom, // 12 texLeft, texBottom, //13 texRight, texBottom, //14 texRight, texBottom //15 }; if ( background && this->viewerTab->isCheckerboardEnabled() && (polygonMode != eDrawPolygonModeWipeRight) ) { bool isblend = GL_GPU::glIsEnabled(GL_BLEND); if (isblend) { GL_GPU::glDisable(GL_BLEND); } this->drawCheckerboardTexture(rod); if (isblend) { GL_GPU::glEnable(GL_BLEND); } } this->bindTextureAndActivateShader(textureIndex, useShader); glCheckError(GL_GPU); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, this->vboVerticesId); GL_GPU::glBufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), vertices); GL_GPU::glEnableClientState(GL_VERTEX_ARRAY); GL_GPU::glVertexPointer(2, GL_FLOAT, 0, 0); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, this->vboTexturesId); GL_GPU::glBufferSubData(GL_ARRAY_BUFFER, 0, 32 * sizeof(GLfloat), renderingTextureCoordinates); GL_GPU::glClientActiveTexture(GL_TEXTURE0); GL_GPU::glEnableClientState(GL_TEXTURE_COORD_ARRAY); GL_GPU::glTexCoordPointer(2, GL_FLOAT, 0, 0); GL_GPU::glDisableClientState(GL_COLOR_ARRAY); GL_GPU::glBindBuffer(GL_ARRAY_BUFFER, 0); GL_GPU::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->iboTriangleStripId); GL_GPU::glDrawElements(GL_TRIANGLE_STRIP, 28, GL_UNSIGNED_BYTE, 0); glCheckErrorIgnoreOSXBug(GL_GPU); GL_GPU::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL_GPU::glDisableClientState(GL_VERTEX_ARRAY); GL_GPU::glDisableClientState(GL_TEXTURE_COORD_ARRAY); glCheckError(GL_GPU); this->unbindTextureAndReleaseShader(useShader); } } // drawRenderingVAO
int SyncTex::SourceToDoc(const WCHAR* srcfilename, UINT line, UINT col, UINT *page, Vec<RectI> &rects) { if (IsIndexDiscarded()) if (RebuildIndex() != PDFSYNCERR_SUCCESS) return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED; assert(this->scanner); ScopedMem<WCHAR> srcfilepath; // convert the source file to an absolute path if (PathIsRelative(srcfilename)) srcfilepath.Set(PrependDir(srcfilename)); else srcfilepath.Set(str::Dup(srcfilename)); if (!srcfilepath) return PDFSYNCERR_OUTOFMEMORY; bool isUtf8 = true; char *mb_srcfilepath = str::conv::ToUtf8(srcfilepath); TryAgainAnsi: if (!mb_srcfilepath) return PDFSYNCERR_OUTOFMEMORY; int ret = synctex_display_query(this->scanner, mb_srcfilepath, line, col); free(mb_srcfilepath); // recent SyncTeX versions encode in UTF-8 instead of ANSI if (isUtf8 && -1 == ret) { isUtf8 = false; mb_srcfilepath = str::conv::ToAnsi(srcfilepath); goto TryAgainAnsi; } if (-1 == ret) return PDFSYNCERR_UNKNOWN_SOURCEFILE; if (0 == ret) return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD; synctex_node_t node; int firstpage = -1; rects.Reset(); while ((node = synctex_next_result(this->scanner)) != NULL) { if (firstpage == -1) { firstpage = synctex_node_page(node); if (firstpage <= 0 || firstpage > engine->PageCount()) continue; *page = (UINT)firstpage; } if (synctex_node_page(node) != firstpage) continue; RectD rc; rc.x = synctex_node_box_visible_h(node); rc.y = synctex_node_box_visible_v(node) - synctex_node_box_visible_height(node); rc.dx = synctex_node_box_visible_width(node), rc.dy = synctex_node_box_visible_height(node) + synctex_node_box_visible_depth(node); rects.Push(rc.Round()); } if (firstpage <= 0) return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD; return PDFSYNCERR_SUCCESS; }
void FixSubgraphSizes(ICluster * cluster, RectD & parentRect) { RectD childRect; for(IClusterSet::const_iterator itr = cluster->GetClusters().begin(); itr != cluster->GetClusters().end(); ++itr) { std::string cluster; FixSubgraphSizes(itr->get(), childRect); } for(IVertexSet::const_iterator itr = cluster->GetVertices().begin(); itr != cluster->GetVertices().end(); ++itr) { if (childRect.IsEmptyArea()) childRect = GetBoundingRect(itr->get()); else childRect.Union(GetBoundingRect(itr->get())); } //if (!GetBoundingRect(cluster).Contains(childRect)) { if (childRect.IsEmptyArea()) childRect = GetBoundingRect(cluster); else childRect.Union(GetBoundingRect(cluster)); if (ElementG * eg = GetElementG(cluster)) { assert(eg->m_polygons.size() == 1); if (eg->m_polygons.size() == 1) { eg->m_polygons[0]->m_points.clear(); eg->m_polygons[0]->SetBoundingBox(RectD()); eg->m_polygons[0]->m_points.push_back(PointD(childRect.GetLeft(), childRect.GetBottom())); eg->m_polygons[0]->m_points.push_back(PointD(childRect.GetLeft(), childRect.GetTop())); eg->m_polygons[0]->m_points.push_back(PointD(childRect.GetRight(), childRect.GetTop())); eg->m_polygons[0]->m_points.push_back(PointD(childRect.GetRight(), childRect.GetBottom())); eg->m_polygons[0]->m_points.push_back(PointD(childRect.GetLeft(), childRect.GetBottom())); } //eg->SetBoundingBox(childRect); eg->CalcBoundingBox(); } //childRect.Union(GetBoundingRect(cluster)); //ElementGPtr elementG = new ElementG(childRect); //cluster->SetProperty(SVG_PROP_ELEMENTG, elementG); } if (parentRect.IsEmptyArea()) parentRect = childRect; else parentRect.Union(childRect); }
static bool PrintToDevice(PrintData& pd, ProgressUpdateUI *progressUI=NULL, AbortCookieManager *abortCookie=NULL) { AssertCrash(pd.engine); if (!pd.engine) return false; AssertCrash(pd.printerName); if (!pd.printerName) return false; BaseEngine& engine = *pd.engine; ScopedMem<WCHAR> fileName; DOCINFO di = { 0 }; di.cbSize = sizeof (DOCINFO); if (gPluginMode) { fileName.Set(ExtractFilenameFromURL(gPluginURL)); // fall back to a generic "filename" instead of the more confusing temporary filename di.lpszDocName = fileName ? fileName : L"filename"; } else di.lpszDocName = engine.FileName(); int current = 1, total = 0; if (pd.sel.Count() == 0) { for (size_t i = 0; i < pd.ranges.Count(); i++) { if (pd.ranges.At(i).nToPage < pd.ranges.At(i).nFromPage) total += pd.ranges.At(i).nFromPage - pd.ranges.At(i).nToPage + 1; else total += pd.ranges.At(i).nToPage - pd.ranges.At(i).nFromPage + 1; } } else { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { if (!BoundSelectionOnPage(pd.sel, pageNo).IsEmpty()) total++; } } AssertCrash(total > 0); if (0 == total) return false; if (progressUI) progressUI->UpdateProgress(current, total); // cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1882 // According to our crash dumps, Cannon printer drivers (caprenn.dll etc.) // are buggy and like to crash during printing with DEP violation // We disable dep during printing to hopefully not crash // TODO: even better would be to print in a separate process so that // crashes during printing wouldn't affect the main process. It's also // much more complicated to implement ScopeDisableDEP scopeNoDEP; // cf. http://blogs.msdn.com/b/oldnewthing/archive/2012/11/09/10367057.aspx ScopeHDC hdc(CreateDC(pd.driverName, pd.printerName, pd.portName, pd.devMode)); if (!hdc) return false; if (StartDoc(hdc, &di) <= 0) return false; // MM_TEXT: Each logical unit is mapped to one device pixel. // Positive x is to the right; positive y is down. SetMapMode(hdc, MM_TEXT); const SizeI paperSize(GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT)); const RectI printable(GetDeviceCaps(hdc, PHYSICALOFFSETX), GetDeviceCaps(hdc, PHYSICALOFFSETY), GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES)); const float dpiFactor = min(GetDeviceCaps(hdc, LOGPIXELSX) / engine.GetFileDPI(), GetDeviceCaps(hdc, LOGPIXELSY) / engine.GetFileDPI()); bool bPrintPortrait = paperSize.dx < paperSize.dy; if (pd.devMode && (pd.devMode.Get()->dmFields & DM_ORIENTATION)) bPrintPortrait = DMORIENT_PORTRAIT == pd.devMode.Get()->dmOrientation; if (pd.sel.Count() > 0) { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { RectD bounds = BoundSelectionOnPage(pd.sel, pageNo); if (bounds.IsEmpty()) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); SizeT<float> bSize = bounds.Size().Convert<float>(); float zoom = min((float)printable.dx / bSize.dx, (float)printable.dy / bSize.dy); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale) zoom = min(dpiFactor, zoom); else if (PrintScaleNone == pd.advData.scale) zoom = dpiFactor; for (size_t i = 0; i < pd.sel.Count(); i++) { if (pd.sel.At(i).pageNo != pageNo) continue; RectD *clipRegion = &pd.sel.At(i).rect; PointI offset((int)((clipRegion->x - bounds.x) * zoom), (int)((clipRegion->y - bounds.y) * zoom)); if (!pd.advData.asImage) { RectI rc((int)(printable.dx - bSize.dx * zoom) / 2 + offset.x, (int)(printable.dy - bSize.dy * zoom) / 2 + offset.y, (int)(clipRegion->dx * zoom), (int)(clipRegion->dy * zoom)); engine.RenderPage(hdc, rc, pd.sel.At(i).pageNo, zoom, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); } else { RenderedBitmap *bmp = NULL; short shrink = 1; do { bmp = engine.RenderBitmap(pd.sel.At(i).pageNo, zoom / shrink, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); if (!bmp || !bmp->GetBitmap()) { shrink *= 2; delete bmp; bmp = NULL; } } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled())); if (bmp) { RectI rc((int)(paperSize.dx - bSize.dx * zoom) / 2 + offset.x, (int)(paperSize.dy - bSize.dy * zoom) / 2 + offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); bmp->StretchDIBits(hdc, rc); delete bmp; } } } if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } EndDoc(hdc); return false; } // print all the pages the user requested for (size_t i = 0; i < pd.ranges.Count(); i++) { int dir = pd.ranges.At(i).nFromPage > pd.ranges.At(i).nToPage ? -1 : 1; for (DWORD pageNo = pd.ranges.At(i).nFromPage; pageNo != pd.ranges.At(i).nToPage + dir; pageNo += dir) { if ((PrintRangeEven == pd.advData.range && pageNo % 2 != 0) || (PrintRangeOdd == pd.advData.range && pageNo % 2 == 0)) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); SizeT<float> pSize = engine.PageMediabox(pageNo).Size().Convert<float>(); int rotation = 0; // Turn the document by 90 deg if it isn't in portrait mode if (pSize.dx > pSize.dy) { rotation += 90; swap(pSize.dx, pSize.dy); } // make sure not to print upside-down rotation = (rotation % 180) == 0 ? 0 : 270; // finally turn the page by (another) 90 deg in landscape mode if (!bPrintPortrait) { rotation = (rotation + 90) % 360; swap(pSize.dx, pSize.dy); } // dpiFactor means no physical zoom float zoom = dpiFactor; // offset of the top-left corner of the page from the printable area // (negative values move the page into the left/top margins, etc.); // offset adjustments are needed because the GDI coordinate system // starts at the corner of the printable area and we rather want to // center the page on the physical paper (default behavior) PointI offset(-printable.x, -printable.y); if (pd.advData.scale != PrintScaleNone) { // make sure to fit all content into the printable area when scaling // and the whole document page on the physical paper RectD rect = engine.PageContentBox(pageNo, Target_Print); RectT<float> cbox = engine.Transform(rect, pageNo, 1.0, rotation).Convert<float>(); zoom = min((float)printable.dx / cbox.dx, min((float)printable.dy / cbox.dy, min((float)paperSize.dx / pSize.dx, (float)paperSize.dy / pSize.dy))); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale && dpiFactor < zoom) zoom = dpiFactor; // make sure that no content lies in the non-printable paper margins RectT<float> onPaper((paperSize.dx - pSize.dx * zoom) / 2 + cbox.x * zoom, (paperSize.dy - pSize.dy * zoom) / 2 + cbox.y * zoom, cbox.dx * zoom, cbox.dy * zoom); if (onPaper.x < printable.x) offset.x += (int)(printable.x - onPaper.x); else if (onPaper.BR().x > printable.BR().x) offset.x -= (int)(onPaper.BR().x - printable.BR().x); if (onPaper.y < printable.y) offset.y += (int)(printable.y - onPaper.y); else if (onPaper.BR().y > printable.BR().y) offset.y -= (int)(onPaper.BR().y - printable.BR().y); } if (!pd.advData.asImage) { RectI rc = RectI::FromXY((int)(paperSize.dx - pSize.dx * zoom) / 2 + offset.x, (int)(paperSize.dy - pSize.dy * zoom) / 2 + offset.y, paperSize.dx, paperSize.dy); engine.RenderPage(hdc, rc, pageNo, zoom, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); } else { RenderedBitmap *bmp = NULL; short shrink = 1; do { bmp = engine.RenderBitmap(pageNo, zoom / shrink, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); if (!bmp || !bmp->GetBitmap()) { shrink *= 2; delete bmp; bmp = NULL; } } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled())); if (bmp) { RectI rc((paperSize.dx - bmp->Size().dx * shrink) / 2 + offset.x, (paperSize.dy - bmp->Size().dy * shrink) / 2 + offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); bmp->StretchDIBits(hdc, rc); delete bmp; } } if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } } EndDoc(hdc); return true; }
RectD DjVuEngineImpl::Transform(RectD rect, int pageNo, float zoom, int rotation, bool inverse) { PointD TL = Transform(rect.TL(), pageNo, zoom, rotation, inverse); PointD BR = Transform(rect.BR(), pageNo, zoom, rotation, inverse); return RectD::FromXY(TL, BR); }
void CurveGui::drawCurve(int curveIndex, int curvesCount) { // always running in the main thread assert( qApp && qApp->thread() == QThread::currentThread() ); AnimItemBasePtr item = _imp->item.lock(); if (!item) { return; } std::vector<float> vertices, exprVertices; const double widgetWidth = _imp->curveWidget->width(); KeyFrameSet keyframes; bool hasDrawnExpr = false; if (item->hasExpression(_imp->dimension, _imp->view)) { //we have no choice but to evaluate the expression at each time for (int i = 0; i < widgetWidth; ++i) { double x = _imp->curveWidget->toZoomCoordinates(i, 0).x(); double y = evaluate(true /*useExpr*/, x); exprVertices.push_back(x); exprVertices.push_back(y); } hasDrawnExpr = true; } QPointF btmLeft = _imp->curveWidget->toZoomCoordinates(0, _imp->curveWidget->height() - 1); QPointF topRight = _imp->curveWidget->toZoomCoordinates(_imp->curveWidget->width() - 1, 0); bool isPeriodic = false; std::pair<double,double> parametricRange = std::make_pair(-std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()); keyframes = getInternalCurve()->getKeyFrames_mt_safe(); isPeriodic = getInternalCurve()->isCurvePeriodic(); parametricRange = getInternalCurve()->getXRange(); if ( keyframes.empty() ) { // Add a horizontal line for constant knobs, except string knobs. KnobIPtr isKnob = boost::dynamic_pointer_cast<KnobI>(item->getInternalAnimItem()); if (isKnob) { KnobStringBasePtr isString = boost::dynamic_pointer_cast<KnobStringBase>(isKnob); if (!isString) { double value = evaluate(false, 0); vertices.push_back(btmLeft.x() + 1); vertices.push_back(value); vertices.push_back(topRight.x() - 1); vertices.push_back(value); } } } else { try { double x1 = 0; double x2; bool isX1AKey = false; KeyFrame x1Key; KeyFrameSet::const_iterator lastUpperIt = keyframes.end(); while ( x1 < (widgetWidth - 1) ) { double x, y; if (!isX1AKey) { x = _imp->curveWidget->toZoomCoordinates(x1, 0).x(); y = evaluate(false, x); } else { x = x1Key.getTime(); y = x1Key.getValue(); } vertices.push_back( (float)x ); vertices.push_back( (float)y ); nextPointForSegment(x, keyframes, isPeriodic, parametricRange.first, parametricRange.second, &lastUpperIt, &x2, &x1Key, &isX1AKey); x1 = x2; } //also add the last point { double x = _imp->curveWidget->toZoomCoordinates(x1, 0).x(); double y = evaluate(false, x); vertices.push_back( (float)x ); vertices.push_back( (float)y ); } } catch (...) { } } // No Expr curve or no vertices for the curve, don't draw anything else if (exprVertices.empty() && vertices.empty()) { return; } AnimationModuleSelectionModelPtr selectionModel = item->getModel()->getSelectionModel(); assert(selectionModel); const AnimItemDimViewKeyFramesMap& selectedKeys = selectionModel->getCurrentKeyFramesSelection(); const KeyFrameWithStringSet* foundThisCurveSelectedKeys = 0; { AnimItemDimViewIndexID k; k.item = item; k.dim = _imp->dimension; k.view = _imp->view; AnimItemDimViewKeyFramesMap::const_iterator foundDimView = selectedKeys.find(k); if (foundDimView != selectedKeys.end()) { foundThisCurveSelectedKeys = &foundDimView->second; } } { GLProtectAttrib<GL_GPU> a(GL_HINT_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT | GL_CURRENT_BIT); // If this is the only curve selected, draw min/max if (foundThisCurveSelectedKeys && selectedKeys.size()) { // Draw y min/max axis so the user understands why the value is clamped Curve::YRange curveYRange = getCurveYRange(); if (curveYRange.min != INT_MIN && curveYRange.min != -std::numeric_limits<double>::infinity() && curveYRange.max != INT_MAX && curveYRange.max != std::numeric_limits<double>::infinity() ) { QColor minMaxColor; minMaxColor.setRgbF(0.398979, 0.398979, 0.398979); GL_GPU::Color4d(minMaxColor.redF(), minMaxColor.greenF(), minMaxColor.blueF(), 1.); GL_GPU::Begin(GL_LINES); GL_GPU::Vertex2d(btmLeft.x(), curveYRange.min); GL_GPU::Vertex2d(topRight.x(), curveYRange.min); GL_GPU::Vertex2d(btmLeft.x(), curveYRange.max); GL_GPU::Vertex2d(topRight.x(), curveYRange.max); GL_GPU::End(); GL_GPU::Color4d(1., 1., 1., 1.); double xText = _imp->curveWidget->toZoomCoordinates(10, 0).x(); _imp->curveWidget->renderText( xText, curveYRange.min, tr("min").toStdString(), minMaxColor.redF(), minMaxColor.greenF(), minMaxColor.blueF(), minMaxColor.alphaF()); _imp->curveWidget->renderText( xText, curveYRange.max, tr("max").toStdString(), minMaxColor.redF(), minMaxColor.greenF(), minMaxColor.blueF(), minMaxColor.alphaF()); } } GL_GPU::Color4f(_imp->color[0], _imp->color[1], _imp->color[2], _imp->color[3]); GL_GPU::PointSize(_imp->lineWidth); GL_GPU::Enable(GL_BLEND); GL_GPU::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_GPU::Enable(GL_LINE_SMOOTH); GL_GPU::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); GL_GPU::LineWidth(1.5); glCheckError(GL_GPU); if (hasDrawnExpr) { drawLineStrip(exprVertices, btmLeft, topRight); GL_GPU::LineStipple(2, 0xAAAA); GL_GPU::Enable(GL_LINE_STIPPLE); } drawLineStrip(vertices, btmLeft, topRight); if (hasDrawnExpr) { GL_GPU::Disable(GL_LINE_STIPPLE); } glCheckErrorIgnoreOSXBug(GL_GPU); //render the name of the curve GL_GPU::Color4f(1.f, 1.f, 1.f, 1.f); double interval = ( topRight.x() - btmLeft.x() ) / (double)curvesCount; double textX = _imp->curveWidget->toZoomCoordinates(15, 0).x() + interval * (double)curveIndex; double textY; CurvePtr internalCurve = _imp->internalCurve.lock(); QString curveName = getName(); QColor thisColor; thisColor.setRgbF(Image::clamp(_imp->color[0], 0., 1.), Image::clamp(_imp->color[1], 0., 1.), Image::clamp(_imp->color[2], 0., 1.)); try { // Use expression to place the text if the curve is not animated textY = evaluate(internalCurve && !internalCurve->isAnimated(), textX); } catch (...) { // if it fails attempt without expression, this will most likely return a constant value textY = evaluate(false /*useExpression*/, textX); } if ( ( textX >= btmLeft.x() ) && ( textX <= topRight.x() ) && ( textY >= btmLeft.y() ) && ( textY <= topRight.y() ) ) { _imp->curveWidget->renderText( textX, textY, curveName.toStdString(), thisColor.redF(), thisColor.greenF(), thisColor.blueF(), thisColor.alphaF()); } GL_GPU::Color4f(_imp->color[0], _imp->color[1], _imp->color[2], _imp->color[3]); //draw keyframes GL_GPU::PointSize(7.f); GL_GPU::Enable(GL_POINT_SMOOTH); KeyFrameWithStringSet::const_iterator foundSelectedKey; if (foundThisCurveSelectedKeys) { foundSelectedKey = foundThisCurveSelectedKeys->end(); } for (KeyFrameSet::const_iterator k = keyframes.begin(); k != keyframes.end(); ++k) { const KeyFrame & key = (*k); // Do not draw keyframes out of range if ( ( key.getTime() < btmLeft.x() ) || ( key.getTime() > topRight.x() ) || ( key.getValue() < btmLeft.y() ) || ( key.getValue() > topRight.y() ) ) { continue; } GL_GPU::Color4f(_imp->color[0], _imp->color[1], _imp->color[2], _imp->color[3]); bool drawKeySelected = false; if (foundThisCurveSelectedKeys) { KeyFrameWithStringSet::const_iterator start = foundSelectedKey == foundThisCurveSelectedKeys->end() ? foundThisCurveSelectedKeys->begin() : foundSelectedKey; foundSelectedKey = std::find_if(start, foundThisCurveSelectedKeys->end(), KeyFrameWithStringTimePredicate(key.getTime())); drawKeySelected = foundSelectedKey != foundThisCurveSelectedKeys->end(); if (!drawKeySelected) { // Also draw the keyframe as selected if it is inside the selection rectangle (but not yet selected) RectD selectionRect = _imp->curveWidget->getSelectionRectangle(); drawKeySelected |= _imp->curveWidget->_imp->eventTriggeredFromCurveEditor && (!selectionRect.isNull() && selectionRect.contains(key.getTime(), key.getValue())); } } // If the key is selected change its color if (drawKeySelected) { GL_GPU::Color4f(0.8f, 0.8f, 0.8f, 1.f); } RectD keyframeBbox = _imp->curveWidget->_imp->getKeyFrameBoundingRectCanonical(_imp->curveWidget->_imp->curveEditorZoomContext, key.getTime(), key.getValue()); // draw texture of the keyframe { AnimationModuleViewPrivate::KeyframeTexture texType = AnimationModuleViewPrivate::kfTextureFromKeyframeType( key.getInterpolation(), drawKeySelected); if (texType != AnimationModuleViewPrivate::kfTextureNone) { _imp->curveWidget->_imp->drawTexturedKeyframe(texType, keyframeBbox, false /*drawdimed*/); } } // Draw tangents if not constant bool drawTangents = drawKeySelected && internalCurve->isYComponentMovable() && (key.getInterpolation() != eKeyframeTypeConstant); if (drawTangents) { QFontMetrics m( _imp->curveWidget->font()); // If interpolation is not free and not broken display with dashes the tangents lines if ( (key.getInterpolation() != eKeyframeTypeFree) && (key.getInterpolation() != eKeyframeTypeBroken) ) { GL_GPU::LineStipple(2, 0xAAAA); GL_GPU::Enable(GL_LINE_STIPPLE); } QPointF leftTanPos, rightTanPos; _imp->curveWidget->getKeyTangentPoints(k, keyframes, &leftTanPos, &rightTanPos); // Draw the derivatives lines GL_GPU::Begin(GL_LINES); GL_GPU::Color4f(1., 0.35, 0.35, 1.); GL_GPU::Vertex2f( leftTanPos.x(), leftTanPos.y() ); GL_GPU::Vertex2f(key.getTime(), key.getValue()); GL_GPU::Vertex2f(key.getTime(), key.getValue()); GL_GPU::Vertex2f( rightTanPos.x(), rightTanPos.y()); GL_GPU::End(); if ( (key.getInterpolation() != eKeyframeTypeFree) && (key.getInterpolation() != eKeyframeTypeBroken) ) { GL_GPU::Disable(GL_LINE_STIPPLE); } // Draw the tangents handles GL_GPU::Begin(GL_POINTS); GL_GPU::Vertex2f( leftTanPos.x(), leftTanPos.y() ); GL_GPU::Vertex2f( rightTanPos.x(), rightTanPos.y()); GL_GPU::End(); // If only one keyframe is selected, also draw the coordinates if (selectedKeys.size() == 1 && foundThisCurveSelectedKeys && foundThisCurveSelectedKeys->size() == 1) { double rounding = std::pow(10., CURVEWIDGET_DERIVATIVE_ROUND_PRECISION); QString leftDerivStr = QString::fromUtf8("l: %1").arg(std::floor( (key.getLeftDerivative() * rounding) + 0.5 ) / rounding); QString rightDerivStr = QString::fromUtf8("r: %1").arg(std::floor( (key.getRightDerivative() * rounding) + 0.5 ) / rounding); double yLeftWidgetCoord = _imp->curveWidget->toWidgetCoordinates(0, leftTanPos.y()).y(); yLeftWidgetCoord += (m.height() + 4); double yRightWidgetCoord = _imp->curveWidget->toWidgetCoordinates(0, rightTanPos.y()).y(); yRightWidgetCoord += (m.height() + 4); GL_GPU::Color4f(1., 1., 1., 1.); glCheckFramebufferError(GL_GPU); _imp->curveWidget->renderText( leftTanPos.x(), _imp->curveWidget->toZoomCoordinates(0, yLeftWidgetCoord).y(), leftDerivStr.toStdString(), 0.9, 0.9, 0.9, 1.); _imp->curveWidget->renderText( rightTanPos.x(), _imp->curveWidget->toZoomCoordinates(0, yRightWidgetCoord).y(), rightDerivStr.toStdString(), 0.9, 0.9, 0.9, 1.); QString coordStr = QString::fromUtf8("x: %1, y: %2"); coordStr = coordStr.arg(key.getTime()).arg(key.getValue()); double yWidgetCoord = _imp->curveWidget->toWidgetCoordinates( 0, key.getValue() ).y(); yWidgetCoord += (m.height() + 4); GL_GPU::Color4f(1., 1., 1., 1.); glCheckFramebufferError(GL_GPU); _imp->curveWidget->renderText( key.getTime(), _imp->curveWidget->toZoomCoordinates(0, yWidgetCoord).y(), coordStr.toStdString(), 0.9, 0.9, 0.9, 1.); } } // drawTangents } // for (KeyFrameSet::const_iterator k = keyframes.begin(); k != keyframes.end(); ++k) { } // GLProtectAttrib(GL_HINT_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT | GL_CURRENT_BIT); glCheckError(GL_GPU); } // drawCurve