void Gui::notifyMouseMove(int ux, int uy) { movie_root* m = _stage; if ( ! _started ) return; if ( _stopped ) return; // A stage pseudopixel is user pixel / _xscale wide boost::int32_t x = (ux-_xoffset) / _xscale; // A stage pseudopixel is user pixel / _xscale high boost::int32_t y = (uy-_yoffset) / _yscale; #ifdef DEBUG_MOUSE_COORDINATES log_debug("mouse @ %d,%d", x, y); #endif if ( m->mouseMoved(x, y) ) { // any action triggered by the // event required screen refresh display(m); } DisplayObject* activeEntity = m->getActiveEntityUnderPointer(); if ( activeEntity ) { if ( activeEntity->isSelectableTextField() ) { setCursor(CURSOR_INPUT); } else if ( activeEntity->allowHandCursor() ) { setCursor(CURSOR_HAND); } else { setCursor(CURSOR_NORMAL); } } else { setCursor(CURSOR_NORMAL); } #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS _xpointer = ux; _ypointer = uy; #endif }
int DisplayList::getNextHighestDepth() const { testInvariant(); int nexthighestdepth=0; for (const_iterator it = _charsByDepth.begin(), itEnd = _charsByDepth.end(); it != itEnd; ++it) { DisplayObject* ch = *it; const int chdepth = ch->get_depth(); if (chdepth >= nexthighestdepth) { nexthighestdepth = chdepth+1; } } return nexthighestdepth; }
void DisplayList::placeDisplayObject(DisplayObject* ch, int depth, as_object* initObj) { assert(!ch->unloaded()); ch->set_invalidated(); ch->set_depth(depth); container_type::iterator it = std::find_if( _charsByDepth.begin(), _charsByDepth.end(), DepthGreaterOrEqual(depth)); if (it == _charsByDepth.end() || (*it)->get_depth() != depth) { // add the new char _charsByDepth.insert(it, DisplayItem(ch)); } else { // remember bounds of old char InvalidatedRanges old_ranges; (*it)->add_invalidated_bounds(old_ranges, true); // make a copy (before replacing) DisplayObject* oldCh = *it; // replace existing char (before calling unload!) *it = DisplayItem(ch); if (oldCh->unload()) { // reinsert removed DisplayObject if needed reinsertRemovedCharacter(oldCh); } else oldCh->destroy(); // extend invalidated bounds ch->extend_invalidated_bounds(old_ranges); } // Give life to this instance ch->stagePlacementCallback(initObj); testInvariant(); }
void Renderer::updateUniforms( DisplayObject obj, Program* program ) { bool prSwitch = false; Program* backup; if(program != NULL) { prSwitch = true; backup = activeProgram; setActiveProgram( program ); } //Uniforms glm::mat4 mv = camera * obj.getTransform(); glm::mat4 mvp = projection * mv; glm::mat3 rot = (glm::mat3)mv; glm::mat3 normal = glm::inverseTranspose(rot); glUniformMatrix4fv(activeProgram->getUniform("mvp"), 1, GL_FALSE, glm::value_ptr(mvp) ); glUniformMatrix4fv(activeProgram->getUniform("mv"), 1, GL_FALSE, glm::value_ptr(mv) ); glUniformMatrix3fv(activeProgram->getUniform("normal_matrix"), 1, GL_FALSE, glm::value_ptr(normal) ); //FOR TESTING PURPOSES ONLY, REMOVE THIS LINE //glUniform4fv(activeProgram->getUniform("LightPosition"), 1, glm::value_ptr( glm::column(-camera, 3) ) ); glUniform4fv(activeProgram->getUniform("LightPosition"), 1, glm::value_ptr( glm::vec3(0,8,0) ) ); //THIS NEEDS TO BE MOVED SOMEWHERE ELSE //THIS NEEDS TO BE DONE ON A PER-MESH BASIS glm::vec3 kD = obj.getModel().materials[0].diffuse; //Light constant glUniform3fv(activeProgram->getUniform("Kd"), 1, glm::value_ptr( kD ) ); //Light intensity //THIS NEEDS TO BE CONTROLLED BY OUR LIGHTING ENGINE. THIS IS ONLY //A STUB AND NEEDS TO BE MOVED SOMEWHERE ELSE WHEN THE PROGRAM //SUPPORTS MORE THAN ONE LIGHT glUniform3fv(activeProgram->getUniform("Ld"), 1, glm::value_ptr( glm::vec3(0.9, 0.9, 0.9) ) ); Program::checkGLErrors("Updating uniforms"); if( prSwitch ) setActiveProgram( backup ); }
DisplayObject* DisplayList::getDisplayObjectAtDepth(int depth) { testInvariant(); for (iterator it = _charsByDepth.begin(), itEnd = _charsByDepth.end(); it != itEnd; ++it) { DisplayObject* ch = *it; // found if (ch->get_depth() == depth) return ch; // non-existent (chars are ordered by depth) if (ch->get_depth() > depth) return 0; } return 0; }
// Removes and returns the child that is found at <arg name="index"/>, // or returns NULL if the index is greater than the number of children. DisplayObject * DisplayObject::removeChildAt(unsigned int index) { DisplayObject * removedChild = NULL; if (index < numChildren()) { std::vector<DisplayObject*>::iterator it; it = _children.begin(); it += index; removedChild = _children[index]; removedChild->setParent( NULL ); _children.erase(it); DisplayObject::release(removedChild); } return removedChild; }
bool Sound_as::getVolume(int& volume) { // TODO: check what takes precedence in case we // have both an attached DisplayObject *and* // some other sound... // if ( _attachedCharacter ) { //log_debug("Sound has an attached DisplayObject"); DisplayObject* ch = _attachedCharacter->get(); if (! ch) { log_debug("Character attached to Sound was unloaded and " "couldn't rebind"); return false; } volume = ch->getVolume(); return true; } // If we're not attached to a DisplayObject we'll need to query // sound_handler for volume. If we have no sound handler, we // can't do much, so we'll return false if (!_soundHandler) { log_debug("We have no sound handler here..."); return false; } // Now, we may be controlling a specific sound or // the final output as a whole. // If soundId is -1 we're controlling as a whole // if (soundId == -1) { volume = _soundHandler->getFinalVolume(); } else { volume = _soundHandler->get_volume(soundId); } return true; }
void DisplayList::placeDisplayObject(DisplayObject* ch, int depth) { assert(!ch->unloaded()); ch->set_invalidated(); ch->set_depth(depth); container_type::iterator it = std::find_if( _charsByDepth.begin(), _charsByDepth.end(), boost::bind(std::not2(DepthLessThan()), _1, depth)); if (it == _charsByDepth.end() || (*it)->get_depth() != depth) { // add the new char _charsByDepth.insert(it, ch); } else { // remember bounds of old char InvalidatedRanges old_ranges; (*it)->add_invalidated_bounds(old_ranges, true); // make a copy (before replacing) DisplayObject* oldCh = *it; // replace existing char (before calling unload!) *it = ch; if (oldCh->unload()) { // reinsert removed DisplayObject if needed reinsertRemovedCharacter(oldCh); } else oldCh->destroy(); // extend invalidated bounds ch->extend_invalidated_bounds(old_ranges); } testInvariant(); }
DisplayObject* DisplayList::getDisplayObjectAtDepth(int depth) const { testInvariant(); for (const_iterator it = _charsByDepth.begin(), itEnd = _charsByDepth.end(); it != itEnd; ++it) { DisplayObject* ch = *it; // Should not be there! if (ch->isDestroyed()) continue; // found if (ch->get_depth() == depth) return ch; // non-existent (chars are ordered by depth) if (ch->get_depth() > depth) return 0; } return 0; }
void Stage::updateChildren() { DisplayObject *obj; int i, total = numChildren(); for(i = 0; i < total; ++i) { obj = children[i]; if(obj->visible) { if(obj->right() > size.x) width( obj->right() ); if(obj->bottom() > size.y) height(obj->bottom()); obj->update(); } } obj = NULL; if(activeScene != NULL) activeScene->updateTime(); }
void ObjectSet::setSelection(std::set<std::pair<uint,uint>> *picks, bool clear) { std::lock(m, DisplayObject::m); if (clear) for (auto i = DisplayObject::begin(); i != DisplayObject::end(); i++) if (i->second->hasSelection()) { i->second->selectObject(_selectionMode, false); signalCheckChange(i->second->patch()); } std::set<Patch *> changedPatches; for (auto p : *picks) { DisplayObject *obj = DisplayObject::getObject(p.first); if (!obj) continue; if (obj->patch()) changedPatches.insert(obj->patch()); switch (_selectionMode) { case SM_PATCH: obj->selectObject(SM_PATCH, true); break; case SM_FACE: obj->selectFaces(true, {p.second}); break; case SM_EDGE: obj->selectEdges(true, {p.second}); break; case SM_POINT: obj->selectPoints(true, {p.second}); break; } } for (auto p : changedPatches) signalCheckChange(p); m.unlock(); DisplayObject::m.unlock(); emit selectionChanged(); }
// private // runs in main thread bool MovieLoader::processCompletedRequest(const Request& r) { //GNASH_REPORT_FUNCTION; boost::intrusive_ptr<movie_definition> md; if (!r.getCompleted(md)) return false; // not completed yet const std::string& target = r.getTarget(); DisplayObject* targetDO = _movieRoot.findCharacterByTarget(target); as_object* handler = r.getHandler(); if (!md) { if (targetDO && handler) { // Signal load error // Tested not to happen if target isn't found at time of loading // as_value arg1(getObject(targetDO)); // FIXME: docs suggest the string can be either "URLNotFound" or // "LoadNeverCompleted". This is neither of them: as_value arg2("Failed to load movie or jpeg"); // FIXME: The last argument is HTTP status, or 0 if no connection // was attempted (sandbox) or no status information is available // (supposedly the Adobe mozilla plugin). as_value arg3(0.0); callMethod(handler, NSV::PROP_BROADCAST_MESSAGE, "onLoadError", arg1, arg2, arg3); } return true; // nothing to do, but completed } const URL& url = r.getURL(); Movie* extern_movie = md->createMovie(*_movieRoot.getVM().getGlobal()); if (!extern_movie) { log_error(_("Can't create Movie instance " "for definition loaded from %s"), url); return true; // completed in any case... } // Parse query string MovieClip::MovieVariables vars; url.parse_querystring(url.querystring(), vars); extern_movie->setVariables(vars); if (targetDO) { targetDO->getLoadedMovie(extern_movie); } else { unsigned int levelno; const int version = _movieRoot.getVM().getSWFVersion(); if (isLevelTarget(version, target, levelno)) { log_debug(_("processCompletedRequest: _level loading " "(level %u)"), levelno); extern_movie->set_depth(levelno + DisplayObject::staticDepthOffset); _movieRoot.setLevel(levelno, extern_movie); } else { log_debug("Target %s of a loadMovie request doesn't exist at " "load complete time", target); return true; } } if (handler && targetDO) { // Dispatch onLoadStart // FIXME: should be signalled before starting to load // (0/-1 bytes loaded/total) but still with *new* // display object as target (ie: the target won't // contain members set either before or after loadClip. callMethod(handler, NSV::PROP_BROADCAST_MESSAGE, "onLoadStart", getObject(targetDO)); // Dispatch onLoadProgress // FIXME: should be signalled on every readNonBlocking() // with a buffer size of 65535 bytes. // size_t bytesLoaded = md->get_bytes_loaded(); size_t bytesTotal = md->get_bytes_total(); callMethod(handler, NSV::PROP_BROADCAST_MESSAGE, "onLoadProgress", getObject(targetDO), bytesLoaded, bytesTotal); // Dispatch onLoadComplete // FIXME: find semantic of last arg callMethod(handler, NSV::PROP_BROADCAST_MESSAGE, "onLoadComplete", getObject(targetDO), as_value(0.0)); // Dispatch onLoadInit // This event must be dispatched when actions // in first frame of loaded clip have been executed. // // Since getLoadedMovie or setLevel above will invoke // construct() and thus queue all actions in first // frame, we'll queue the // onLoadInit call next, so it happens after the former. // std::auto_ptr<ExecutableCode> code( new DelayedFunctionCall(targetDO, handler, NSV::PROP_BROADCAST_MESSAGE, "onLoadInit", getObject(targetDO))); getRoot(*handler).pushAction(code, movie_root::PRIORITY_DOACTION); } return true; }
void DisplayObjectContainer::renderChildren(lua_State *L) { if (!visible) { return; } // containers can set a new view to render into, but we must restore the // current view after, so take a snapshot int viewRestore = GFX::Graphics::getView(); // set the current view we will be rendering into. if (viewRestore != _view) { GFX::Graphics::setView(_view); } renderState.alpha = parent ? parent->renderState.alpha * alpha : alpha; renderState.cachedClipRect = parent ? parent->renderState.cachedClipRect : (unsigned short)-1; int docidx = lua_gettop(L); lua_rawgeti(L, docidx, (int)childrenOrdinal); lua_rawgeti(L, -1, LSINDEXVECTOR); int childrenVectorIdx = lua_gettop(L); int numChildren = lsr_vector_get_length(L, -2); if (_depthSort && ((int)sSortBucket.size() < numChildren)) { sSortBucket.resize(numChildren); } // Is there a cliprect? If so, set it. if ((clipX != 0) || (clipY != 0) || (clipWidth != 0) || (clipHeight != 0)) { GFX::QuadRenderer::submit(); Matrix res; DisplayObject *stage = this; while (stage->parent) { stage = stage->parent; } getTargetTransformationMatrix(NULL, &res); int x1 = (int) ((float)clipX * res.a + res.tx) ; int y1 = (int) ((float)clipY * res.d + res.ty); int x2 = (int) ((float)clipWidth * res.a); int y2 = (int) ((float)clipHeight * res.d); renderState.cachedClipRect = GFX::Graphics::setClipRect(x1, y1, x2, y2); } else { GFX::Graphics::setClipRect(renderState.cachedClipRect); } for (int i = 0; i < numChildren; i++) { lua_rawgeti(L, childrenVectorIdx, i); DisplayObject *dobj = (DisplayObject *)lualoom_getnativepointer(L, -1); lua_rawgeti(L, -1, LSINDEXTYPE); dobj->type = (Type *)lua_topointer(L, -1); lua_pop(L, 1); dobj->validate(L, lua_gettop(L)); if (!_depthSort) { renderType(L, dobj->type, dobj); } else { sSortBucket[i].index = i; sSortBucket[i].displayObject = dobj; } // pop instance lua_pop(L, 1); } if (_depthSort) { qsort(sSortBucket.ptr(), numChildren, sizeof(DisplayObjectSort), DisplayObjectSortFunction); for (int i = 0; i < numChildren; i++) { DisplayObjectSort *ds = &sSortBucket[i]; lua_rawgeti(L, childrenVectorIdx, ds->index); renderType(L, ds->displayObject->type, ds->displayObject); // pop instance lua_pop(L, 1); } } lua_settop(L, docidx); // Restore clip state. if ((clipX != 0) || (clipY != 0) || (clipWidth != 0) || (clipHeight != 0)) { GFX::QuadRenderer::submit(); GFX::Graphics::clearClipRect(); } // restore view if (viewRestore != _view) { GFX::Graphics::setView(viewRestore); } }
BaseDisplayObject(const DisplayObject<Derived, Deleter>& derived) : _handle(derived.Handle()) { }
bool ObjectSet::addPatchFromStream(std::ifstream &stream, File *file) { Go::ObjectHeader head; QString error = QString("%2 in '%1'").arg(file->fn()); QString logString; try { head.read(stream); } catch (...) { emit log(error.arg("Unrecognized object header"), LL_ERROR); return false; } DisplayObject *obj = NULL; DisplayObject::m.lock(); switch (head.classType()) { case Go::Class_SplineVolume: { Go::SplineVolume *v = new Go::SplineVolume(); try { v->read(stream); } catch (...) { emit log(error.arg("Unable to parse SplineVolume"), LL_ERROR); delete v; return false; } obj = new Volume(v); break; } case Go::Class_SplineSurface: { Go::SplineSurface *s = new Go::SplineSurface(); try { s->read(stream); } catch (...) { emit log(error.arg("Unable to parse SplineSurface"), LL_ERROR); delete s; return false; } obj = new Surface(s); break; } case Go::Class_SplineCurve: { Go::SplineCurve *c = new Go::SplineCurve(); try { c->read(stream); } catch (...) { emit log(error.arg("Unable to parse SplineCurve"), LL_ERROR); delete c; return false; } obj = new Curve(c); break; } default: emit log(error.arg(QString("Unrecognized class type %1").arg(head.classType())), LL_ERROR); } if (!obj) { DisplayObject::m.unlock(); return false; } m.lock(); QModelIndex index = createIndex(file->indexInParent(), 0, file); beginInsertRows(index, file->nChildren(), file->nChildren()); Patch *patch = new Patch(obj, file); endInsertRows(); m.unlock(); DisplayObject::m.unlock(); while (!obj->initialized()) { emit requestInitialization(obj); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } if (!obj->initialized()) { emit log("Failed to initialize display object", LL_ERROR); delete obj; return true; // Can continue } emit update(); return true; }
void DynamicShape::display(Renderer& renderer, const DisplayObject& inst) const { renderer.drawShape(_shape, inst.get_world_cxform(), inst.getWorldMatrix()); }
/** Creates a matrix that represents the transformation from the local coordinate system * to another. If you pass a 'resultMatrix', the result will be stored in this matrix * instead of creating a new object. */ void DisplayObject::getTargetTransformationMatrix(DisplayObject *targetSpace, Matrix *resultMatrix) { if (!resultMatrix) { return; } resultMatrix->identity(); if (transformDirty) { updateLocalTransform(); } if (targetSpace == this) { return; } if ((targetSpace == parent) || ((targetSpace == NULL) && (parent == NULL))) { resultMatrix->copyFrom(&transformMatrix); return; } DisplayObject *base = this; while (base->parent) { base = base->parent; } DisplayObject *currentObject = NULL; if ((targetSpace == NULL) || (targetSpace == base)) { // targetCoordinateSpace 'null' represents the target space of the base object. // -> move up from this to base currentObject = this; while (currentObject != targetSpace) { if (currentObject->transformDirty) { currentObject->updateLocalTransform(); } resultMatrix->concat(¤tObject->transformMatrix); currentObject = currentObject->parent; } return; } else if (targetSpace->parent == this) // optimization { targetSpace->getTargetTransformationMatrix(this, resultMatrix); resultMatrix->invert(); return; } // 1. find a common parent of this and the target space DisplayObject *commonParent = NULL; currentObject = this; while (currentObject) { DisplayObject *target = targetSpace; while (target) { if (target == currentObject) { commonParent = target; break; } target = target->parent; } if (commonParent) { break; } currentObject = currentObject->parent; } lmAssert(commonParent, "Object not connected to target."); //else throw new ArgumentError("Object not connected to target"); // 2. move up from this to common parent currentObject = this; while (currentObject != commonParent) { if (currentObject->transformDirty) { currentObject->updateLocalTransform(); } resultMatrix->concat(¤tObject->transformMatrix); currentObject = currentObject->parent; } if (commonParent == targetSpace) { return; } // 3. now move up from target until we reach the common parent Matrix helperMatrix; //helperMatrix.identity(); currentObject = targetSpace; while (currentObject != commonParent) { helperMatrix.concat(¤tObject->transformMatrix); currentObject = currentObject->parent; } // 4. now combine the two matrices helperMatrix.invert(); resultMatrix->concat(&helperMatrix); }
void DisplayList::replaceDisplayObject(DisplayObject* ch, int depth, bool use_old_cxform, bool use_old_matrix) { testInvariant(); //GNASH_REPORT_FUNCTION; assert(!ch->unloaded()); ch->set_invalidated(); ch->set_depth(depth); container_type::iterator it = std::find_if(_charsByDepth.begin(), _charsByDepth.end(), DepthGreaterOrEqual(depth)); DisplayItem di(ch); if (it == _charsByDepth.end() || (*it)->get_depth() != depth) { _charsByDepth.insert(it, di); } else { // Make a copy (before replacing) DisplayObject* oldch = *it; InvalidatedRanges old_ranges; if (use_old_cxform) { // Use the cxform from the old DisplayObject. ch->set_cxform(oldch->get_cxform()); } if (use_old_matrix) { // Use the SWFMatrix from the old DisplayObject. ch->setMatrix(oldch->getMatrix(), true); } // remember bounds of old char oldch->add_invalidated_bounds(old_ranges, true); // replace existing char (before calling unload) *it = di; // Unload old char if (oldch->unload()) { // reinsert removed DisplayObject if needed reinsertRemovedCharacter(oldch); } else oldch->destroy(); // extend invalidated bounds // WARNING: when a new Button DisplayObject is added, // the invalidated bounds computation will likely // be bogus, as the actual DisplayObject shown is not instantiated // until ::stagePlacementCallback for buttons (I'd // say this is a bug in Button). ch->extend_invalidated_bounds(old_ranges); } // Give life to this instance ch->stagePlacementCallback(); testInvariant(); }
QVariant ObjectSet::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); Node *node = static_cast<Node *>(index.internalPointer()); if (role == Qt::DisplayRole && index.column() == 0) return node->displayString(); if (role == Qt::ForegroundRole && index.column() == 0) { ComponentType type; if (node->type() == NT_COMPONENTS) type = static_cast<Components *>(node)->cType(); else if (node->type() == NT_COMPONENT) type = static_cast<Components *>(node->parent())->cType(); else return QVariant(); return QBrush(QColor(modeMatch(_selectionMode, type) ? "black" : "silver")); } if (role == Qt::CheckStateRole && index.column() == 2) { switch (node->type()) { case NT_FILE: { bool foundUnselected = false, foundSelected = false; for (auto n : node->children()) { DisplayObject *obj = static_cast<Patch *>(n)->obj(); foundUnselected |= !obj->fullSelection(_selectionMode); foundSelected |= obj->hasSelection(); if (foundUnselected && foundSelected) return Qt::PartiallyChecked; } return foundSelected ? Qt::Checked : Qt::Unchecked; } case NT_PATCH: { DisplayObject *obj = static_cast<Patch *>(node)->obj(); return QVariant(obj->fullSelection(_selectionMode) ? Qt::Checked : (obj->hasSelection() ? Qt::PartiallyChecked : Qt::Unchecked)); } case NT_COMPONENT: if (modeMatch(_selectionMode, static_cast<Components *>(node->parent())->cType())) return static_cast<Component *>(node)->isSelected() ? Qt::Checked : Qt::Unchecked; return QVariant(); } } if (role == Qt::DecorationRole && index.column() == 1) { if (node->type() == NT_PATCH) { DisplayObject *obj = static_cast<Patch *>(node)->obj(); QString base = ":/icons/%1_%2.png"; switch (obj->type()) { case OT_VOLUME: base = base.arg("volume"); break; case OT_SURFACE: base = base.arg("surface"); break; case OT_CURVE: base = base.arg("curve"); break; } base = base.arg(obj->isFullyVisible(false) ? "full" : (obj->isInvisible(false) ? "hidden" : "partial")); return QIcon(base); } else if (node->type() == NT_FILE) { bool allInvisible = true, allVisible = true; for (auto n : node->children()) { DisplayObject *obj = static_cast<Patch *>(n)->obj(); allInvisible &= obj->isInvisible(false); allVisible &= obj->isFullyVisible(false); if (!allInvisible && !allVisible) return QIcon(":/icons/file_partial.png"); } return QIcon(allVisible ? ":/icons/file_full.png" : ":/icons/file_hidden.png"); } } return QVariant(); }
int main(int /*argc*/, char** /*argv*/) { gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance(); dbglogfile.setVerbosity(1); string filename = string(TGTDIR) + string("/") + string(INPUT_FILENAME); tester.reset(new MovieTester(filename)); URL baseURL(filename); URL mediaURL(MEDIADIR"/"); URL lynchURL("lynch.swf", mediaURL); URL greenURL("green.jpg", mediaURL); URL offspringURL("offspring.swf", mediaURL); std::string url; gnash::RcInitFile& rc = gnash::RcInitFile::getDefaultInstance(); rc.addLocalSandboxPath(MEDIADIR); root = tester->getRootMovie(); assert(root); check_equals(root->get_frame_count(), 2); check_equals(root->get_current_frame(), 0); tester->advance(); check_equals(root->get_current_frame(), 1); // Verify that 'coverart' exists and is empty DisplayObject* coverartch = const_cast<DisplayObject*>(tester->findDisplayItemByName(*root, "coverart")); MovieClip* coverart = coverartch->to_movie(); check(coverart); url = coverart->get_root()->url(); check_equals(coverart->get_root()->url(), baseURL.str()); // Check scribbling on the empty canvas checkScribbling(); // Click on the first (lynch) tester->movePointerTo(80, 80); check(tester->isMouseOverMouseEntity()); tester->pressMouseButton(); // Wait for the movie to load // TODO: drop this test and use a self-containment instead do { usleep(500); // give it some time... tester->advance(); // loads (should) happen on next advance coverartch = const_cast<DisplayObject*>(tester->findDisplayItemByName(*root, "coverart")); } while (coverartch->to_movie() == coverart); coverart = coverartch->to_movie(); check_equals(coverart->get_root()->url(), lynchURL.str()); tester->depressMouseButton(); // Check scribbling on the lynch checkScribbling(); // Run 'coverart' tests.. tester->movePointerTo(640,180); tester->click(); tester->advance(); // Click on the second (green) tester->movePointerTo(280, 80); check(tester->isMouseOverMouseEntity()); tester->click(); // Wait for the movie to load // TODO: drop this test and use a self-containment instead do { usleep(500); // give it some time... tester->advance(); // loads (should) happen on next advance coverartch = const_cast<DisplayObject*>(tester->findDisplayItemByName(*root, "coverart")); } while (coverartch->to_movie() == coverart); coverart = coverartch->to_movie(); check_equals(coverart->get_root()->url(), greenURL.str()); // TODO: find a way to test if the jpeg is really displayed // (like turn it into a mouse-event-handling char and use isMouseOverActiveEntity ?) // Check scribbling on the jpeg checkScribbling(); // Run 'coverart' tests.. tester->movePointerTo(640,180); tester->click(); tester->advance(); // Click on the third (offspring) tester->movePointerTo(480, 80); check(tester->isMouseOverMouseEntity()); tester->click(); // Wait for the movie to load // TODO: drop this test and use a self-containment instead do { usleep(500); // give it some time... tester->advance(); // loads (should) happen on next advance coverartch = const_cast<DisplayObject*>(tester->findDisplayItemByName(*root, "coverart")); } while (coverartch->to_movie() == coverart); coverart = coverartch->to_movie(); check_equals(coverart->get_root()->url(), offspringURL.str()); // Check scribbling on the offspring checkScribbling(); // Run 'coverart' tests.. tester->movePointerTo(640,180); tester->click(); tester->advance(); // Get summary ... tester->pressKey(key::SHIFT); tester->click(); tester->advance(); tester->releaseKey(key::SHIFT); // Consistency checking VM& vm = getVM(*getObject(root)); as_value eot; // It's an swf6, so lowercase 'END_OF_TEST' bool endOfTestFound = getObject(root)->get_member(getURI(vm, "end_of_test"), &eot); check(endOfTestFound); if ( endOfTestFound ) { check_equals(eot.to_bool(8), true); } }